none
Extracting partial whatif output and emailing it RRS feed

  • Question

  • This script below auto protects new VM's in a cluster when ran. It can be found at https://technet.microsoft.com/en-us/library/ff634200.aspx?f=255&MSPPError=-2147217396

    Instead of running the script against our production environment, I thought it's be nice to test first is using -whatif. I have modified the script and appended whatif to "action" items in the script as seen below.

    How do I get just the portion that reads "What if: Adds data source <vm name> to protection group <protection group>"

    Script I am running with whatif switches:

    # AddNewClusteredVM.ps1
    # This script is expected to work with DPM 2010 Beta

    # 1. Parameters supplied to the script
    param([string] $ProductionCluster = "", [string] $PGName = "") 

    # 2. Failures are registered in Applocation events in the DPM server.
    trap [Exception] { 
    $log = Get-EventLog -List | Where-Object { $_.Log -eq "Application" }
    $log.Source = "AddNewClusteredVM"
    $log.WriteEntry("TRAPPED: $error[0]", [system.Diagnostics.EventLogEntryType]::Error,9911) 
    $Error[0] #show on console
    exit 
    }

    # 3. Prompt for missing parameters
    if(!$ProductionCluster) 
    {
    $Productioncluster = "clustername.fqdn"
    }
    if(!$PGName) 
    {
    $PGName = "PG in DPM"
    }

    $dpmservername = &"hostname"
    connect-dpmserver $dpmservername

    # Do not modify this line
    $tape = "Short-term using tape"

    # Hyper-V Writer guid
    $guid = "66841cd4-6ded-4f4b-8f17-fd23f8ddc3de"

    # 4. Search for the protection group name passed as input and exit if it was not found
    $PGList = @(Get-ProtectionGroup $dpmservername)
    $PG = $PGlist | where { $_.FriendlyName -eq $PGName}
    if (!$PG) { Throw "Specified protection group [$PGname] is not found!" }

    # 5. Obtain the list of protected clusters on this DPM server
    $Cluster = Get-ProductionCLuster $dpmservername | ? { $_.ClusterName -eq $ProductionCluster}
    if (!$Cluster) { Throw "Specified cluster name  [$ProductionCluster] is not found!" }

    $RGList = @()
    $joblist = @()
    $global:DSlist = @()

    # 6. Run inquiry on cluster to get list of available resource groups
    write-host "Running Inquiry on" $Cluster.clusterName
    $RGlist = Get-ProductionVirtualName $Cluster

    # 7. Need to run inquiry on each resource group
    foreach ($RG in $RGlist)
    {
    write-host "Running Inquiry on" $RG.NetBiosName
    # 7.1 Inquiry is run in parallel and the event mechanism is used to signal completion of inquiry.
    # 'DataSourceDetectionEvent' event signals the completion of inquiry. and the data sources obtained are added to the global variable
    $joblist += register-objectevent -inputobject $RG -Eventname DatasourceDetectionEvent -Action {$global:DSlist += $($Event.SourceEventArgs.ProtectableObjects)}

    # 7.2 Run inquiry
    Get-Datasource -ProductionServer $RG -Inquire -Async
    }

    # 8. Scan through each job created in the previous loop
    foreach ($job in $joblist)
    {
    # 8.1 Waiting for the job to run
    while ($job.State -eq "NotStarted")
    {
    write-host "Waiting for inquiry to complete" $global:DSlist.count "item(s) obtained..."
    sleep 1
    }
    }
    # 8.2 Inquiry complete on all resource groups

    write-host "Inquiry listed" $global:DSlist.count "item(s)..."

    # 9. If object is a data source and of type Hyper-V and is currently not protected add to list of unprotected VMs
    $unprotectedDSList = @(($global:DSList) | ? {$($_.Type.IsDatasource) -and ($($_.Type.Id) -match $guid) -and ! $($_.Protected)})

    # 10. Exit if there are no unprotected VMs
    if ($unprotectedDSList.count -lt 1) 
    {
    write-host "No new datasources found!"
    exit 1
    }

    # 11. Obtain a modifiable protection group type
    $MPG = Get-ModifiableProtectionGroup $PG

    # 12. Perform the following for each new VM to add to protection
    foreach ($ds in $unprotectedDSList)
    {
    write-host "Adding data source" $ds.Name "to" $MPG.FriendlyName
    $npg = Add-ChildDatasource -ProtectionGroup $MPG -ChildDatasource $ds -WhatIf

    # 12.1 Disk Allocation is skipped in case of short term protection being to tape.
    if($MPG.protectionmethod -eq $tape) {continue;}
    $x = Get-DatasourceDiskAllocation -Datasource $ds
    Set-DatasourceDiskAllocation -Datasource $ds -ProtectionGroup $MPG -WhatIf
    }

    # 13 Note that this step will force immediate replica creation irrespective of the PG policy.
    Set-ReplicaCreationMethod -ProtectionGroup $MPG -Now -whatif

    write-host "Adding new Hyper-V data sources to" $MPG.FriendlyName

    # 14 Save the changes to the protection group. Replica creation will be triggered immediately.
    Set-protectiongroup $MPG -whatif

    disconnect-dpmserver $dpmservername -erroraction silentlycontinue
    "Exiting from script"

    By running this, I retrieve the following results:

    Running Inquiry on <clustername.fqdn>

    Running Inquiry on Cluster Group
    Running Inquiry on <VM name>

    Running Inquiry on <VM name>

    Running Inquiry on <VM name>

    ..........

    Inquiry listed 1 item(s)...
    Adding data source <vm name> to <PG name>

    What if: Adds data source <vm name> to <PG name>
    What if: Modifies disk allocation for data source <vm name>
    Adding data source <vm name> to <PG name>
    What if: Adds data source <vm name> to <PG name>
    What if: Modifies disk allocation for data source <vm name>
    What if: Sets replica creation method for protection group <PG name>
    Adding new Hyper-V data sources to <PG name>
    What if: Commits changes made to protection group <PG name>
    Exiting from script

    Monday, September 21, 2015 10:11 PM

Answers

  • Hi,

    This should solve parsing of the Transcript file.

    Get-Content  PowerShell_transcript.20150923171935.txt | Select-String "What If:"

    Read more about Select-String:

    https://technet.microsoft.com/en-us/library/hh849903.aspx

    And as for the numbering your script content, use Ctrl+G or a better editor which will have numbering already, like PowerShell_ise


    Regards,

    Satyajit

    Please“Vote As Helpful” if you find my contribution useful or “MarkAs Answer” if it does answer your question. That will encourage me - and others - to take time out to help you.


    • Edited by Satyajit321 Wednesday, September 23, 2015 11:59 AM
    • Marked as answer by Script..U must Wednesday, September 23, 2015 8:10 PM
    Wednesday, September 23, 2015 11:56 AM

All replies

  • What does "How do I get" mean. What is it you are trying to get?

    \_(ツ)_/

    Monday, September 21, 2015 10:49 PM
  • jrv,

    Thanks for looking at the script. What I mean by how do i get was where in the script can I add a Start-Transcript and Stop-Transcript and have the results emailed to me? I am specifically interested in getting the email to read all the whatif actions from my results.


    example email:

    to:

    from:

    subject: VM's from "$ProductionCluster" not backed up in DPM

    body:

    What if: Adds data source <vm name> to <PG name>
    What if: Modifies disk allocation for data source <vm name>
    Adding data source <vm name> to <PG name>
    What if: Adds data source <vm name> to <PG name>
    What if: Modifies disk allocation for data source <vm name>
    What if: Sets replica creation method for protection group <PG name>
    Adding new Hyper-V data sources to <PG name>
    What if: Commits changes made to protection group <PG name>


    Tuesday, September 22, 2015 1:33 PM
  • Start-Transcript at the beginning and stop it at the end.  Parse the file and email it.  What is the issue?

    \_(ツ)_/

    Tuesday, September 22, 2015 3:05 PM
  • I ran the script with my start/stop transcript but I am unable to parse what I need. Instead, I get a bunch of random lines from my log file that are useless.

    Here is what I've added after step 13 in the original script:

    #14 generate log file
    $now = Get-Date
    $logfile = "C:\Scripts\Logs\Cluster1\" + $now.ToString("yyyy-MM-dd") + ".log"
    Start-Transcript -path $logfile -force

    #14.1 email as HTML
    $emailFrom = "server@mycompany.com"
    $emailTo = "me@mycompany.com"
    $subject = "Unprotected VM's in" + "$Productioncluster"
    $smtpServer = "smtp.mycompany.com"
    $log = Get-Content $logfile
    $body = New-Object System.Text.StringBuilder
    foreach($line in $log)
    {
        [void] $body.AppendLine($line.ToString())
    }
    $smtp = new-object Net.Mail.SmtpClient($smtpServer)
    $smtp.Send($emailFrom, $emailTo, $subject, $body.ToString())

    I get an email with:

    **********************

    Windows PowerShell transcript start

    Start time: 20150922132742

    Username: myaccount

    RunAs User: myaccount

    Machine: DPMServer (Microsoft Windows NT 6.2.9200.0) Host Application: C:\Windows\system32\WindowsPowerShell\v1.0\PowerShell_ISE.exe

    Process ID: 9592

    **********************

    Transcript started, output file is C:\Scripts\Logs\cluster12015-09-22.log

    Transcript started, output file is C:\Scripts\Logs\Cluster12015-09-22.log

    Transcript started, output file is C:\Scripts\Logs\Cluster12015-09-22.log

    Tuesday, September 22, 2015 6:39 PM
  • Why can't you use PowerShell to send an email.  Just send the file contents as a body.

    $body=Get-Contents $logfile |Out-String


    \_(ツ)_/


    • Edited by jrv Tuesday, September 22, 2015 9:37 PM
    Tuesday, September 22, 2015 9:30 PM
  • I see no good reason for all of the numbered comments.  They make you code I'm possible to read and understand.

    Look for blogs on how to format code and how to comment code.  It will help you to reduce the confusion.


    \_(ツ)_/

    Tuesday, September 22, 2015 9:33 PM
  • Half the lines and easier to understand.  Start with this and try to provide good structure to your code.  Use the code as the description by choosing good names for things.

    param (
    	[string]$ProductionCluster='clustername.fqdn',
    	[string]$PGName='PG in DPM'
    )
    
    $dpmservername = $env:COMPUTERNAME
    connect-dpmserver $dpmservername
    
    # Do not modify this line
    $tape = 'Short-term using tape'
    
    # Hyper-V Writer guid
    $guid = "66841cd4-6ded-4f4b-8f17-fd23f8ddc3de"
    
    if($PG=@(Get-ProtectionGroup $dpmservername | where{ $_.FriendlyName -eq $PGName }){
    	if($Cluster = Get-ProductionCLuster $dpmservername|Where{ $_.ClusterName -eq $ProductionCluster }){
    		$RGList = @()
    		$joblist = @()
    		$global:DSlist = @()
    		write-host "Running Inquiry on" $Cluster.clusterName
    		$RGlist = Get-ProductionVirtualName $Cluster
    		foreach ($RG in $RGlist) {
    			write-host "Running Inquiry on$($RG.NetBiosName)"
    			$joblist += register-objectevent -inputobject $RG -Eventname DatasourceDetectionEvent -Action { $global:DSlist += $($Event.SourceEventArgs.ProtectableObjects) }	
    			Get-Datasource -ProductionServer $RG -Inquire -Async
    		}
    
    		foreach ($job in $joblist) {
    			while ($job.State -eq "NotStarted") {
    				write-host "Waiting for inquiry to complete $($global:DSlist.count) item(s) obtained..."
    				sleep 1
    			}
    		}
    
    		write-host "Inquiry listed" $global:DSlist.count "item(s)..."
    		$unprotectedDSList = @(($global:DSList) | ? { $($_.Type.IsDatasource) -and ($($_.Type.Id) -match $guid) -and ! $($_.Protected) })
    		if ($unprotectedDSList.count -lt 1) {
    			write-host "No new datasources found!"
    			exit 1
    		}
    
    		$MPG = Get-ModifiableProtectionGroup $PG
    		foreach ($ds in $unprotectedDSList) {
    			write-host "Adding data source" $ds.Name "to" $MPG.FriendlyName
    			$npg = Add-ChildDatasource -ProtectionGroup $MPG -ChildDatasource $ds -WhatIf
    			if ($MPG.protectionmethod -eq $tape) { continue; }
    			$x = Get-DatasourceDiskAllocation -Datasource $ds
    			Set-DatasourceDiskAllocation -Datasource $ds -ProtectionGroup $MPG -WhatIf
    		}
    
    		#This step will force immediate replica creation irrespective of the PG policy.
    		Set-ReplicaCreationMethod -ProtectionGroup $MPG -Now -whatif
    		write-host "Adding new Hyper-V data sources to" $MPG.FriendlyName
    		Set-protectiongroup $MPG -whatif
    		disconnect-dpmserver $dpmservername -erroraction silentlycontinue
    		Write-Host 'Exiting from script'
    	}
    }
    
    


    \_(ツ)_/

    Tuesday, September 22, 2015 9:52 PM
  • Hi,

    This should solve parsing of the Transcript file.

    Get-Content  PowerShell_transcript.20150923171935.txt | Select-String "What If:"

    Read more about Select-String:

    https://technet.microsoft.com/en-us/library/hh849903.aspx

    And as for the numbering your script content, use Ctrl+G or a better editor which will have numbering already, like PowerShell_ise


    Regards,

    Satyajit

    Please“Vote As Helpful” if you find my contribution useful or “MarkAs Answer” if it does answer your question. That will encourage me - and others - to take time out to help you.


    • Edited by Satyajit321 Wednesday, September 23, 2015 11:59 AM
    • Marked as answer by Script..U must Wednesday, September 23, 2015 8:10 PM
    Wednesday, September 23, 2015 11:56 AM
  • This is exactly what I was after.  Thanks!
    Wednesday, September 23, 2015 8:10 PM