New Question
 
 
PRTG Network Monitor

Intuitive to Use.
Easy to manage.

200.000 administrators have chosen PRTG to monitor their network. Find out how you can reduce cost, increase QoS and ease planning, as well.

Free PRTG
Download >>

 

What is this?

This knowledgebase contains questions and answers about PRTG Network Monitor and network monitoring in general. You are invited to get involved by asking and answering questions!

Learn more

 

Top Tags


View all Tags


Monitor Shadow Copies age

Votes:

0

Your Vote:

Up

Down

Hello, guys!

Is it possible to monitor the age of volume shadow copies in a windows server?

age shadow-copy windows

Created on Jun 22, 2015 1:37:23 PM by  peresbr (0) 1



Best Answer

Accepted Answer

Votes:

0

Your Vote:

Up

Down

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

Created on Mar 8, 2017 8:04:14 PM by  Florian Rossmark (4,187) 3 2



10 Replies

Votes:

0

Your Vote:

Up

Down

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 :)

Created on Jun 22, 2015 2:00:32 PM by  Stephan Linke [Paessler Support]



Accepted Answer

Votes:

0

Your Vote:

Up

Down

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

Created on Mar 8, 2017 8:04:14 PM by  Florian Rossmark (4,187) 3 2



Votes:

0

Your Vote:

Up

Down

Hi Florian,

Thanks for your submission! I added to to our script world ;)

Created on Mar 9, 2017 9:08:47 AM by  Stephan Linke [Paessler Support]



Votes:

0

Your Vote:

Up

Down

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..

Created on Nov 28, 2017 3:28:11 PM by  Adb (0)



Votes:

0

Your Vote:

Up

Down

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

Created on Nov 28, 2017 4:29:28 PM by  Stephan Linke [Paessler Support]



Votes:

0

Your Vote:

Up

Down

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>

Created on Mar 22, 2018 2:56:55 AM by  Perry Chan (0) 1



Votes:

0

Your Vote:

Up

Down

Hi Perry,

What PowerShell Version do you have installed? Issue $PSVersionTable to find out and let me know.


Kind regards,
Stephan Linke, Tech Support

Created on Mar 22, 2018 11:51:09 AM by  Stephan Linke [Paessler Support]



Votes:

0

Your Vote:

Up

Down

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.

Created on Aug 23, 2018 7:51:56 PM by  Hector (0) 1



Votes:

0

Your Vote:

Up

Down

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.

Created on Aug 24, 2018 1:43:12 PM by  Florian Rossmark (4,187) 3 2



Votes:

1

Your Vote:

Up

Down

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 by  dbenz04 (10)

Last change on Mar 11, 2019 7:32:53 AM by  Stephan Linke [Paessler Support]



Please log in or register to enter your reply.


Disclaimer: The information in the Paessler Knowledge Base comes without warranty of any kind. Use at your own risk. Before applying any instructions please exercise proper system administrator housekeeping. You must make sure that a proper backup of all your data is available.