Hello, guys!
Is it possible to monitor the age of volume shadow copies in a windows server?
Votes:
Hello, guys!
Is it possible to monitor the age of volume shadow copies in a windows server?
Votes:
This is my solution for it - we monitor specific drives we enabled for shadow copy and wanted to see amount of shadows, newest should be within x hours and oldest should be at a minimum n hours - those limits can be configured with the limitations rather easily.
Main issue is - we talk about WMI modules that are only available in x64 if you use a x64 system. Now PRTG is executing sensors in x86, even thought it is installed on x64. Now, played around a while and came up with this simple solution.
Parameters for the parser-script (the one you need to execute) are: %host C: %host D: etc.
Parser script, needs to be in EXEXML directory: Name: Get-ShadowCopyStatsXMLx64parser.cmd
@"%SystemRoot%\Sysnative\WindowsPowerShell\v1.0\powershell.exe" -c "&'C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML\Get-ShadowCopyStatsXML.ps1' -Servername %1 -Driveletter %2"
PS1 script, should to be in EXEXML directory - if not, adjust path in parser script: Name: Get-ShadowCopyStatsXML.ps1
Param( $ServerName, $DriveLetter ) Begin { $script:CurrentErrorActionPreference = $ErrorActionPreference $ShadowCopyStats = @() Function GetShadowCopyStats { Param($Computer) try { Import-Module @("Microsoft.PowerShell.Management","PSDiagnostics") $WMITarget = "$Computer" Get-WmiObject -Class "Win32_ComputerSystem" -Property "Name" -ComputerName $WMITarget | out-null If ($? -eq $False) { $bWMIConnection = $False $WMITarget = "$Computer." Get-WmiObject -Class "Win32_ComputerSystem" -Property "Name" -ComputerName $WMITarget | out-null If($? -eq $False){$bWMIConnection = $False}Else{$bWMIConnection = $True} } $xml = '<prtg>' $Volumes = gwmi Win32_Volume -Property SystemName,DriveLetter,DeviceID -Filter "DriveType=3" -ComputerName $WMITarget | Select SystemName,@{n="DriveLetter";e={$_.DriveLetter.ToUpper()}},DeviceID | Sort DriveLetter $ShadowCopies = gwmi Win32_ShadowCopy -Property VolumeName,InstallDate,Count -ComputerName $WMITarget | Select VolumeName,InstallDate,Count, @{n="CreationDate";e={$_.ConvertToDateTime($_.InstallDate)}} } catch [Exception] { #Write-Warning $_.Exception|format-list -force $Error[0].Exception.StackTrace $Error[0].Exception.InnerException.StackTrace $Error[0].StackTrace write-error "hello" } If($Volumes) { ForEach($Volume in $Volumes) { If($Volume.DriveLetter -eq $DriveLetter) { $VolumeShares = $VolumeShadowStorage = $DiffVolume = $VolumeShadowCopies = $Null $VolumeShadowCopies = $ShadowCopies | ?{$_.VolumeName -eq $Volume.DeviceID} | Sort InstallDate If($VolumeShadowCopies) { $xml += '<result><channel>ShadowCopyCount</channel><value>' + (($VolumeShadowCopies | Measure-Object -Property Count -Sum).Sum) + '</value></result>' $AgeOldest = New-TimeSpan -Start (($VolumeShadowCopies | Select -First 1).CreationDate) -End (Get-Date) $AgeLatest = New-TimeSpan -Start (($VolumeShadowCopies | Select -Last 1).CreationDate) -End (Get-Date) $xml += '<result><channel>OldestShadowCopy</channel><value>' + [math]::Round($AgeOldest.TotalHours,0) + '</value><unit>TimeHours</unit></result>' $xml += '<result><channel>LatestShadowCopy</channel><value>' + [math]::Round($AgeLatest.TotalHours,0) + '</value><unit>TimeHours</unit></result>' }Else{ $xml += '<result><channel>ShadowCopyCount</channel><value>0</value></result>' $xml += '<result><channel>OldestShadowCopy</channel><value>0</value><unit>TimeHours</unit></result>' $xml += '<result><channel>LatestShadowCopy</channel><value>0</value><unit>TimeHours</unit></result>' } If($VolumeShadowStorage -Or $ShowAllVolumes){$Output += $Object} } } } $xml += '</prtg>' WriteXmlToScreen $xml } Function WriteXmlToScreen ([xml]$xml) { $StringWriter = New-Object System.IO.StringWriter; $XmlWriter = New-Object System.Xml.XmlTextWriter $StringWriter; $XmlWriter.Formatting = "indented"; $xml.WriteTo($XmlWriter); $XmlWriter.Flush(); $StringWriter.Flush(); Write-Output $StringWriter.ToString(); } } Process { If($ServerName) {ForEach($Server in $ServerName){$ShadowCopyStats += GetShadowCopyStats $Server}} Else {$ShadowCopyStats += GetShadowCopyStats $_} } End { $ErrorActionPreference = $script:CurrentErrorActionPreference $ShadowCopyStats }
PS: yes, the PS1 could be further optimized, but it took me already a while to find out the main issue was the x86/x64 combination, what is not possible - see Microsoft articles in MSDN/KB for more information while the Shadow-Copy WMI modules are only available in x64 on a x64 system.
Hope this helps others with the same challenge :-)
Regards, Florian Rossmark
12 Replies
Votes:
The following script should get what you want - Get-ShadowCopyStats.ps1
Note that you have to use it in conjunction with the EXE/Script (Advanced) sensor and modify it to output the data in proper PRTG XML Format,
see http://your-prtg-server/api.htm?tabid=7 for the details :)
Votes:
This is my solution for it - we monitor specific drives we enabled for shadow copy and wanted to see amount of shadows, newest should be within x hours and oldest should be at a minimum n hours - those limits can be configured with the limitations rather easily.
Main issue is - we talk about WMI modules that are only available in x64 if you use a x64 system. Now PRTG is executing sensors in x86, even thought it is installed on x64. Now, played around a while and came up with this simple solution.
Parameters for the parser-script (the one you need to execute) are: %host C: %host D: etc.
Parser script, needs to be in EXEXML directory: Name: Get-ShadowCopyStatsXMLx64parser.cmd
@"%SystemRoot%\Sysnative\WindowsPowerShell\v1.0\powershell.exe" -c "&'C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML\Get-ShadowCopyStatsXML.ps1' -Servername %1 -Driveletter %2"
PS1 script, should to be in EXEXML directory - if not, adjust path in parser script: Name: Get-ShadowCopyStatsXML.ps1
Param( $ServerName, $DriveLetter ) Begin { $script:CurrentErrorActionPreference = $ErrorActionPreference $ShadowCopyStats = @() Function GetShadowCopyStats { Param($Computer) try { Import-Module @("Microsoft.PowerShell.Management","PSDiagnostics") $WMITarget = "$Computer" Get-WmiObject -Class "Win32_ComputerSystem" -Property "Name" -ComputerName $WMITarget | out-null If ($? -eq $False) { $bWMIConnection = $False $WMITarget = "$Computer." Get-WmiObject -Class "Win32_ComputerSystem" -Property "Name" -ComputerName $WMITarget | out-null If($? -eq $False){$bWMIConnection = $False}Else{$bWMIConnection = $True} } $xml = '<prtg>' $Volumes = gwmi Win32_Volume -Property SystemName,DriveLetter,DeviceID -Filter "DriveType=3" -ComputerName $WMITarget | Select SystemName,@{n="DriveLetter";e={$_.DriveLetter.ToUpper()}},DeviceID | Sort DriveLetter $ShadowCopies = gwmi Win32_ShadowCopy -Property VolumeName,InstallDate,Count -ComputerName $WMITarget | Select VolumeName,InstallDate,Count, @{n="CreationDate";e={$_.ConvertToDateTime($_.InstallDate)}} } catch [Exception] { #Write-Warning $_.Exception|format-list -force $Error[0].Exception.StackTrace $Error[0].Exception.InnerException.StackTrace $Error[0].StackTrace write-error "hello" } If($Volumes) { ForEach($Volume in $Volumes) { If($Volume.DriveLetter -eq $DriveLetter) { $VolumeShares = $VolumeShadowStorage = $DiffVolume = $VolumeShadowCopies = $Null $VolumeShadowCopies = $ShadowCopies | ?{$_.VolumeName -eq $Volume.DeviceID} | Sort InstallDate If($VolumeShadowCopies) { $xml += '<result><channel>ShadowCopyCount</channel><value>' + (($VolumeShadowCopies | Measure-Object -Property Count -Sum).Sum) + '</value></result>' $AgeOldest = New-TimeSpan -Start (($VolumeShadowCopies | Select -First 1).CreationDate) -End (Get-Date) $AgeLatest = New-TimeSpan -Start (($VolumeShadowCopies | Select -Last 1).CreationDate) -End (Get-Date) $xml += '<result><channel>OldestShadowCopy</channel><value>' + [math]::Round($AgeOldest.TotalHours,0) + '</value><unit>TimeHours</unit></result>' $xml += '<result><channel>LatestShadowCopy</channel><value>' + [math]::Round($AgeLatest.TotalHours,0) + '</value><unit>TimeHours</unit></result>' }Else{ $xml += '<result><channel>ShadowCopyCount</channel><value>0</value></result>' $xml += '<result><channel>OldestShadowCopy</channel><value>0</value><unit>TimeHours</unit></result>' $xml += '<result><channel>LatestShadowCopy</channel><value>0</value><unit>TimeHours</unit></result>' } If($VolumeShadowStorage -Or $ShowAllVolumes){$Output += $Object} } } } $xml += '</prtg>' WriteXmlToScreen $xml } Function WriteXmlToScreen ([xml]$xml) { $StringWriter = New-Object System.IO.StringWriter; $XmlWriter = New-Object System.Xml.XmlTextWriter $StringWriter; $XmlWriter.Formatting = "indented"; $xml.WriteTo($XmlWriter); $XmlWriter.Flush(); $StringWriter.Flush(); Write-Output $StringWriter.ToString(); } } Process { If($ServerName) {ForEach($Server in $ServerName){$ShadowCopyStats += GetShadowCopyStats $Server}} Else {$ShadowCopyStats += GetShadowCopyStats $_} } End { $ErrorActionPreference = $script:CurrentErrorActionPreference $ShadowCopyStats }
PS: yes, the PS1 could be further optimized, but it took me already a while to find out the main issue was the x86/x64 combination, what is not possible - see Microsoft articles in MSDN/KB for more information while the Shadow-Copy WMI modules are only available in x64 on a x64 system.
Hope this helps others with the same challenge :-)
Regards, Florian Rossmark
Votes:
Hi Florian,
Thanks for your submission! I added to to our script world ;)
Votes:
Hi,
First of all thank you for this script, unfortunatly the sensor does not work :
This sensor requires the PowerShell 2.0 (or higher) to be installed on the probe system.
(GetShadowCopyStats : hello At C:\Program Files (x86)\PRTG Network Monitor\Custom
Sensors\EXEXML\Get-ShadowCopyStatsXML.ps1:89 char:55 + {ForEach($Server in
$ServerName){$ShadowCopyStats += GetShadowCopyStats $Server ... +
~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:)
[Write-Error], WriteErrorExcep tion + FullyQualifiedErrorId :
Microsoft.PowerShell.Commands.WriteErrorExceptio n,GetShadowCopyStats WriteXmlToScreen
: Cannot process argument transformation on parameter 'xml'. Cannot convert value "</prtg>"
to type "System.Xml.XmlDocument". Error: "Unexpected end tag. Line 1, position 3."
At C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML\
Get-ShadowCopyStatsXML.ps1:71 char:30 + WriteXmlToScreen $xml +
~~~~ + CategoryInfo : InvalidData: (:) [WriteXmlToScreen], ParameterBi
ndingArgumentTransformationException + FullyQualifiedErrorId :
ParameterArgumentTransformationError,WriteXmlToS creen at
System.Management.ManagementScope.Initialize() at System.Management
.ManagementObjectSearcher.Initialize() at System.Management.ManagementObjectSearcher.Get() at
Microsoft.PowerShell.Commands.GetWmiObjectCommand.BeginProcessing() at
System.Management.Automation.Cmdlet.DoBeginProcessing() at
System.Management.Automation.CommandProcessorBase.DoBegin() ) (code: PE181)
If I launch the script manualy on the PRTG server I have to following :
<prtg>
<result>
<channel>ShadowCopyCount</channel>
<value>12</value>
</result>
<result>
<channel>OldestShadowCopy</channel>
<value>177</value>
<unit>TimeHours</unit>
</result>
<result>
<channel>LatestShadowCopy</channel>
<value>4</value>
<unit>TimeHours</unit>
</result>
</prtg>
How can I solve this? PowerShell is of course installed on the probe server and on the remote one..
Votes:
You need to install the latest version of the Windows Management Framework, as it contains the latest PowerShell version. Yours is seemingly rather old and due for an update anyway :) It should work then.
Kind regards,
Stephan Linke, Tech Support Team
Votes:
Hi all. Trying to implement this. The sensor returns 0 data when it runs. The following appears in the sensor logs. Running the parser command works on the server console.
Appreciate any help.
Thanks, Perry
+ ~~~~~~~~~~ + CategoryInfo : InvalidData: (:) [Add-Type], InvalidOperationExc eption + FullyQualifiedErrorId : COMPILER_ERRORS,Microsoft.PowerShell.Commands.Ad dTypeCommand
Import-Module : The module to process 'PSDiagnostics', listed in field 'ModuleToProcess/RootModule' of module manifest 'C:\Windows\system32\WindowsPow erShell\v1.0\Modules\PSDiagnostics\PSDiagnostics.psd1' was not processed because no valid module was found in any module directory. At C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML\Get-ShadowCopyStatsXML.ps1:14 char:9 + Import-Module @("Microsoft.PowerShell.Management","PSDiagnost ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ResourceUnavailable: (PSDiagnostics:String) [Imp ort-Module], PSInvalidOperationException + FullyQualifiedErrorId : Modules_ModuleFileNotFound,Microsoft.PowerShell. Commands.ImportModuleCommand
gwmi : Initialization failure At C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML\Get-ShadowCopyStatsXML.ps1:28 char:33 + ... dowCopies = gwmi Win32_ShadowCopy -Property VolumeName,InstallDate,Co ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], Managemen tException + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.C ommands.GetWmiObjectCommand
<prtg> <result> <channel>ShadowCopyCount</channel> <value>0</value> </result> <result> <channel>OldestShadowCopy</channel> <value>0</value> <unit>TimeHours</unit> </result> <result> <channel>LatestShadowCopy</channel> <value>0</value> <unit>TimeHours</unit> </result> </prtg>
Votes:
Hi Perry,
What PowerShell Version do you have installed? Issue $PSVersionTable to find out and let me know.
Kind regards,
Stephan Linke, Tech Support
Votes:
When I run it from the Powershell in the PRTG server works correctly and returns the XML to me but when I do it from the advanced script sensor it does not return any value and it does timeout. What I want to monitor is a connected USB device, a biometric device, that does not appear in the main panel of My PC.
Votes:
Hector - a biometric USB device? Sorry for my confusion - but what does this have to do with ShadowCopies?
Please activate the logging for the sensor and if necessary extend the timeout for the sensor - those information will help to determine why the sensor isn't working but your manual execution of the script.
More detailed information will help as well.
Votes:
I was having some trouble getting this script set up as a PRTG sensor, it was returning 0s because of this error:
gwmi : Initialization failure At C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML\Get-ShadowCopyStatsXML.ps1:28 char:33 + $ShadowCopies = gwmi Win32_ShadowCopy -Property VolumeName,Insta ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~ + CategoryInfo : InvalidOperation: (:) [Get-WmiObject], Managemen tException + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.C ommands.GetWmiObjectCommand
I tried several different things to try to resolve this error, but I ended up compiling it to an exe using this: https://gallery.technet.microsoft.com/PS2EXE-GUI-Convert-e7cb69d5
The exe worked great with PRTG - returns exactly the numbers I expect. Not sure why the exe works for me, but the powershell script doesn't.
Created on Mar 8, 2019 8:06:37 PM
Last change on Mar 11, 2019 7:32:53 AM by
Stephan Linke [Paessler Support]
Votes:
I'm having issues with the script in PRTG. The script manually runs without issues.
PS C:\Program Files (x86)\PRTG Network Monitor\Custom Sensors\EXEXML> .\Get-ShadowCopyStatsXML.ps1 cfs f:
<prtg>
<result>
<channel>ShadowCopyCount</channel>
<value>64</value>
</result>
<result>
<channel>OldestShadowCopy</channel>
<value>767</value>
<unit>TimeHours</unit>
</result>
<result>
<channel>LatestShadowCopy</channel>
<value>3</value>
<unit>TimeHours</unit>
</result>
</prtg>
But I get the following error in PRTG.
XML: XML Parser mismatch: Wanted </>, got </prtg> -- JSON: The returned JSON does not match the expected structure (Invalid JSON.). (code: PE231)
PRTG Version: PRTG Network Monitor 19.2.50.2842 x64 Auto-Update Status[8/19/2019 12:51:41 PM] The downloaded PRTG version (19.2.50.2842) is not newer than your current version (19.2.50.2842). Operating System: Microsoft Windows Server 2016 Standard (10.0 Build 14393), 8 CPUs (8x x64 Model 79 Step 1), code page "Windows-1252", on "LSI UCSB-MRAID12G SCSI DISK DEVICE"
Votes:
@Everyone having trouble with errors in PRTG: XML: XML Parser mismatch: Wanted </>, got </prtg> -- JSON: The returned JSON does not match the expected structure (Invalid JSON.). (code: PE231)
mbright solution works.
Created a .exe file from the .ps1 with PS2EXE-GUI. Put the EXE in D:\PRTG Network Monitor\Custom Sensors\EXEXML
Created in PRTG a custom sensor "Exe/script advanced" In settings, be sure to select "Write result to disks" and "Use Windows credentials of parent device" as the script has to be run with allowed user, which is not always the user running PRTG probe.
EXE runs pretty quickly on multiple hosts without trouble.
Thanks Florian Rossmark and mbright for this great custom check and help :)
©2024 Paessler AG Terms & Conditions Privacy Policy Legal Notice Download & Install
Add comment