Configure Smtp Virtual Server in windows Server using Powershell-(Relay,Connection) - powershell

Using powershell I have to enable SMTP and
Add relay Ip
Add connection IPs
Set Access Control Authentication
I found following code for the above operation
$GetSMTP = Get-CimInstance -Namespace "root\MicrosoftIISv2" -Class "IISSMTPServerSetting" -Filter "Name ='SmtpSvc/1'"
$RelayIps = #(10,92,32,83,127,0,0,1)
$GetSMTP.RelayIpList = $RelayIps
Set-CimInstance -InputObject $GetSMTP
$GetSMTP
$GetSMTP = Get-CimInstance -Namespace "root\MicrosoftIISv2" -Class "IIsIPSecuritySetting" -Filter "Name ='SmtpSvc/1'"
$NewConnectionIps = #(
"10.92.32.80, 10.92.32.81";
"10.92.32.83,127.0.0.1";
)
$GetSMTP.ipgrant += $NewConnectionIps
Set-CimInstance -InputObject $GetSMTP
$GetSMTP
The above powershell code executed successfully and it list as it is added.
But when i connect to smtp server, the following error is throwing
I have a found a solution to solve the above issue, To delete the folders inside "C:\inetpub\mailroot" and where i am able to start the default Smtp Virtual Server, but again facing an issue while click smtp vitrual server properties

Loading Feature Installation Modules
Import-Module ServerManager
Installing Features
Add-WindowsFeature SMTP-Server,Web-Mgmt-Console,WEB-WMI
Adding Relay , connection IPs and Authentication Basic for SMTP
$Networkip =#()
$Networks = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName localhost | ? {$_.IPEnabled}
foreach($Network in $Networks) { $Networkip = $Network.IpAddress[0] }
Adding Relay and Authentication Basic for SMTP
$ipblock= #(24,0,0,128,
32,0,0,128,
60,0,0,128,
68,0,0,128,
1,0,0,0,
76,0,0,0,
0,0,0,0,
0,0,0,0,
1,0,0,0,
0,0,0,0,
2,0,0,0,
1,0,0,0,
4,0,0,0,
0,0,0,0,
76,0,0,128,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
255,255,255,255)
$ipList = #()
$octet = #()
$connectionips=$arg[0]
$ipList = "127.0.0.1"
$octet += $ipList.Split(".")
$octet += $Networkip.Split(".")
$ipblock[36] +=2
$ipblock[44] +=2;
$smtpserversetting = get-wmiobject -namespace root\MicrosoftIISv2 -computername localhost -Query "Select * from IIsSmtpServerSetting"
$ipblock += $octet
$smtpserversetting.AuthBasic=1
$smtpserversetting.RelayIpList = $ipblock
$smtpserversetting.put()
Adding Connection for SMTP
$connectionips="10.10.10.10"
$checkArray =$connectionips.split(",")
if($checkArray -notcontains $Networkip)
{
$connectionips += ","+$Networkip
}
$connectionipbuild=#()
$ipArray=$connectionips.split(",")
foreach ($ip in $ipArray)
{
$connectionipbuild +=$ip+",255.255.255.255;"
}
$iisObject = new-object System.DirectoryServices.DirectoryEntry("IIS://localhost/SmtpSvc/1")
$ipSec = $iisObject.Properties["IPSecurity"].Value
# We need to pass values as one element object arrays
[Object[]] $grantByDefault = #()
$grantByDefault += , $false # <<< We're setting it to false
$ipSec.GetType().InvokeMember("GrantByDefault", $bindingFlags, $null, $ipSec, $grantByDefault);
$iisObject.Properties["IPSecurity"].Value = $ipSec
$iisObject.CommitChanges()
$iisObject = new-object System.DirectoryServices.DirectoryEntry("IIS://localhost/SmtpSvc/1")
$ipSec = $iisObject.Properties["IPSecurity"].Value
$bindingFlags = [Reflection.BindingFlags] "Public, Instance, GetProperty"
$isGrantByDefault = $ipSec.GetType().InvokeMember("GrantByDefault", $bindingFlags, $null, $ipSec, $null);
# to set an iplist we need to get it first
if($isGrantByDefault)
{
$ipList = $ipSec.GetType().InvokeMember("IPDeny", $bindingFlags, $null, $ipSec, $null);
}
else
{
$ipList = $ipSec.GetType().InvokeMember("IPGrant", $bindingFlags, $null, $ipSec, $null);
}
# Add a single computer to the list:
$ipList = $ipList + $connectionipbuild
# This is important, we need to pass an object array of one element containing our ipList array
[Object[]] $ipArray = #()
$ipArray += , $ipList
# Now update
$bindingFlags = [Reflection.BindingFlags] "Public, Instance, SetProperty"
if($isGrantByDefault)
{
$ipList = $ipSec.GetType().InvokeMember("IPDeny", $bindingFlags, $null, $ipSec, $ipArray);
}
else
{
$ipList = $ipSec.GetType().InvokeMember("IPGrant", $bindingFlags, $null, $ipSec, $ipArray);
}
$iisObject.Properties["IPSecurity"].Value = $ipSec
$iisObject.CommitChanges()

In addition to PonVimal's answer (accepted):
This solution uses Get-NetworkAddress function from Indented.NetworkTools
If you would like to specify relay for a group of computers instead of single address you can use System.DirectoryServices in a following manner (thanks to this answer as well):
$IpRelayList = #("192.168.1.0, 255.255.0.0",
"127.3.4.0, 255.255.255.192")
#adding relays
$iisObject = new-object System.DirectoryServices.DirectoryEntry("IIS://localhost/smtpsvc/1")
$relays = $iisObject.Properties["RelayIpList"].Value
$bindingFlags = [Reflection.BindingFlags] "Public, Instance, GetProperty"
$ipList = $relays.GetType().InvokeMember("IPGrant", $bindingFlags, $null, $relays, $null);
#if relay list is empty we are retrieving host subnets and adding to relay
$Networkip =#()
if($IpRelayList.Count -eq 0)
{
$Networks = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName localhost | ? {$_.IPEnabled}
foreach($Network in $Networks)
{
$line = Get-NetworkAddress $Network.IpAddress[0] $Network.IpSubnet[0]
$line = $line + ", " + $Network.IpSubnet[0]
$Networkip += $line
}
}
$ipList = $Networkip + $IpRelayList
# This is important, we need to pass an object array of one element containing our ipList array
[Object[]] $ipArray = #()
$ipArray += , $ipList
# Now update
$bindingFlags = [Reflection.BindingFlags] "Public, Instance, SetProperty"
$ipList = $relays.GetType().InvokeMember("IPGrant", $bindingFlags, $null, $relays, $ipArray);
$iisObject.Properties["RelayIpList"].Value = $relays
$iisObject.CommitChanges()

In addition to PonVimal's answer (accepted):
I also wanted the SMTPSVC service to be automatic and came up with an idempotent script that ensures that the service is not only installed but also set to automatic and started so that any subsequent machine restarts does not require me to manually start the service.
# ----- Converting service: "Simple Mail Transfer Protocol" to be automatic from manual ------
$ServiceName= "SMTPSVC"
If (Get-Service $ServiceName -ErrorAction SilentlyContinue) {
If ((Get-Service $ServiceName).StartType -ne "Automatic") {
If ((Get-Service $ServiceName).Status -eq 'Running') {
Stop-Service $ServiceName
"Stopping $ServiceName"
} Else {
"ServiceName found, and it is stopped."
}
Set-Service -Name $ServiceName -StartupType "Automatic"
Do{
"Starting service: $ServiceName"
sc.exe start "$ServiceName"
start-sleep -s 5
$ServiceStatus = (get-service -name $ServiceName)
}
Until ($ServiceStatus.Status -eq "running")
"Service Started: $ServiceName"
}
If ((Get-Service $ServiceName).Status -eq 'Running') {
"`n$ServiceName configured as automatic and running`n"
} Else {
Do{
"Starting service: $ServiceName"
sc.exe start "$ServiceName"
start-sleep -s 5
$ServiceStatus = (get-service -name $ServiceName)
}
Until ($ServiceStatus.Status -eq "running")
"Service Started: $ServiceName"
}
} Else {
"$ServiceName not found"
}
# Test to check if the service is configured correctly and is running
If (Get-Service $ServiceName) {
If ((Get-Service $ServiceName).StartType -ne "Automatic") {
throw "$ServiceName is not configured as automatic"
}
If ((Get-Service $ServiceName).Status -ne 'Running') {
throw "$ServiceName is not running"
}
"`n$ServiceName configured as automatic and running`n"
}

This is actually possible, and more complicated than one might think. This magical relay IP list object has some collection lengths hard-coded into it.
Here's part of my script that I used after I figured out that oddity.
param(
[Parameter(ValueFromRemainingArguments=$true)][object[]]$AllowedIPs
)
$SMTPServerWmi = Get-WmiObject IISSmtpServerSetting -namespace "ROOT\MicrosoftIISv2" | Where-Object { $_.name -like "SmtpSVC/1" }
$SMTPServerWmi.RelayIpList = #(24,0,0,128,
32,0,0,128,
60,0,0,128,
68,0,0,128,
1,0,0,0,
76,0,0,0,
0,0,0,0,
0,0,0,0,
1,0,0,0,
$AllowedIPs.Count,0,0,0,
2,0,0,0,
($AllowedIPs.Count + 1),0,0,0,
4,0,0,0,
0,0,0,0,
76,0,0,128,
0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
255,255,255,255) + $AllowedIPs.ForEach({ $_.Split(".")})
$SMTPServerWmi.Put()
If those values aren't correct, the UI may show your IPs and a lot of random junk, crash, or become broken such that you cannot use it to remove the items from the list using the UI.

Related

Powershell lookup RAM information on remote computer and save Partnumbers in to diffent variable

I have a simple script that can pull RAM partnumbers from a remote computer and search google for it. But it does not work as intended. If there's only 1 RAM module installed in the remote computer, it works great google opens with the search result for the Partnumber, yay!.
if there are more than 1 RAM module installed in the remote computer, the first Partnumber in the variable gets searched for in Google. The 2'nd, 3'rd, 4'th partnumber gets typed in to Chrome tab 2,3,4 as an address.
How can I get Chrome to search for all Partnumbers via Google?
My script:
$ComputerName = Read-Host "Write Computer Name"
Get-WmiObject Win32_PhysicalMemory -computername $ComputerName
$ToChrome = Read-Host 'Do you want to search Google for the Partnumber(s)? Y Or N'
if ($ToChrome -eq 'Y') {$Partnumber = Get-WmiObject Win32_PhysicalMemory -computername $ComputerName | select -expandproperty Partnumber
Start-Process "chrome.exe" ("https://www.google.com/search?q=$Partnumber")}
if ($ToChrome -eq 'n') {Continue}
That is because chrome.exe interprets the space between the part numbers as new addresses.
I took the liberty to pimp the script with try&catch,a logfile output and the computername as a parameter so that you can call it as Get-MemoryPropertyAndSearchWithGoogle.ps1 -ComputerName ComputerName1
For my testing I used the attribute DeviceLocator as my PartNumber was empty.
#Get-MemoryPropertyAndSearchWithGoogle.ps1
Param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[string]$ComputerName
)
$ErrorPreference='Stop'
$ErrorActionPreference='Stop'
$LogFilePath = "C:\Temp\$((Get-Date).ToString("yyyy-MM-dd"))$($ComputerName)Get-MemoryPropertyAndSearchWithGoogle.log"
[string]$LogFileString = ""
#$Property = "PartNumber"
$Property = "DeviceLocator"
$ErrorExists = $false
$ComputerMemoryObjects = #()
try
{
$ComputerMemoryObjects = Get-WmiObject Win32_PhysicalMemory -ComputerName $ComputerName -Property *
$LogFileString += "$((Get-Date).ToString("yyyy-MM-dd_HH:mm:ss"))#INF#Get-WmiObject Win32_PhysicalMemory -ComputerName $($ComputerName)`n"
}
catch
{
$LogFileString += "$((Get-Date).ToString("yyyy-MM-dd_HH:mm:ss"))#ERR#$($error[0].exception.message)`n"
$ErrorExists = $true
}
[string]$SearchString = ""
foreach ($SingleComputerMemoryObject in $ComputerMemoryObjects)
{
if ($SearchString)
{
$SearchString += "+OR+"
}
$SearchString += "$($SingleComputerMemoryObject.$Property)"
}
$ToChrome = Read-Host 'Do you want to search Google for the Partnumber(s)? Y Or N'
if ($ToChrome -eq 'Y')
{
if ($SearchString)
{
try
{
Start-Process "chrome.exe" ("https://www.google.com/search?q=$($SearchString)")
$LogFileString += "$((Get-Date).ToString("yyyy-MM-dd_HH:mm:ss"))#INF#chrome.exe started with searchstring:`"$($SearchString)`"`n"
}
catch
{
$LogFileString += "$((Get-Date).ToString("yyyy-MM-dd_HH:mm:ss"))#ERR#$($error[0].exception.message)`n"
$ErrorExists = $true
}
}
else
{
$LogFileString += "$((Get-Date).ToString("yyyy-MM-dd_HH:mm:ss"))#INF#`$SearchString is empty`n"
}
}
if (!($ErrorExists))
{
$LogFileString += "$((Get-Date).ToString("yyyy-MM-dd_HH:mm:ss"))#INF#ScriptCompletedWithoutErrors`n"
}
$LogFileString | Out-File $LogFilePath
$LogFileString
You get multiple objects from Get-WmiObject. You need a loop if you want to do something for each of them.
Also, URL-encoding things that you put into a URL is a good idea. and maybe putting it in double-quotes won't hurt.
Add-Type -AssemblyName System.Web # for [System.Web.HttpUtility]::UrlEncode()
$ComputerName = Read-Host "Write Computer Name"
$installed_memory = Get-WmiObject Win32_PhysicalMemory -ComputerName $ComputerName | Select-Object Manufacturer,PartNumber,SerialNumber,DeviceLocator,Capacity
$installed_memory | Format-Table -AutoSize
$ToChrome = Read-Host 'Do you want to search Google for the Partnumber(s)? Y Or N'
if ($ToChrome -eq 'Y') {
$unique_numbers = $installed_memory.Partnumber.Trim() | Sort-Object -Unique
foreach ($number in $unique_numbers) {
$query = [System.Web.HttpUtility]::UrlEncode('"' + $number + '"')
Start-Process chrome.exe "https://www.google.com/search?q=$query"
}
}
Powershell has a handy convenience feature: When you have an array of objects, you can query nested properties from all of them in one go.
For example, if there are 4 Win32_PhysicalMemory objects in $installed_memory, then
$installed_memory.Partnumber.Trim()
gives you 4 readily trimmed part numbers in a single step.

Ping then DNS lookup before I purge an asset

So I am trying to Purge IPs from tool that we use. Before I can purge the assets we need to make sure the host is not pingable and not in DNS. I am new to PS and cant seem to wrap my head around on doing this. Any help is greatly appreciated. I have been doing this as a manual process by pinging the list of IPs and hostnames and doing a nslookup in cmd prompt before selecting the IPs that are needing to be removed. I have about 13k IPs left to do.
Update:
I want to implement this portion into it. Where In cell A it will have the IP
cell B will let me know if it is up or down. And Cell D will let me know if it is DNS aswell. Below is the script I got for pinging and checking if up or down and checking AD to see if the hostname is still in AD. I want it similar to this.. Please excuse my english
$path = ".\results.xls"
$objExcel = new-object -comobject excel.application
if (Test-Path $path)
{
$objWorkbook = $objExcel.WorkBooks.Open($path)
$objWorksheet = $objWorkbook.Worksheets.Item(1)
}
else {
$objWorkbook = $objExcel.Workbooks.Add()
$objWorksheet = $objWorkbook.Worksheets.Item(1)
}
$objExcel.Visible = $True
#########Add Header####
$objWorksheet.Cells.Item(1, 1) = "HostName"
$objWorksheet.Cells.Item(1, 2) = "Result"
$objWorksheet.Cells.Item(1, 3) = "MachineIP"
$objWorksheet.Cells.Item(1, 4) = "Active Directory"
$machines = Get-Content .\machinelist.txt
$row=2
$machines | foreach-object{
$ping = $null
$iname = $null
$machine = $_
$ping = Test-Connection $machine -Count 1 -ea silentlycontinue
$checkAD = try {$comp = Get-ADComputer -Identity $machine -ErrorAction
Stop
if ($comp){"Yes"}else{throw}
}
catch {"No"}
$objWorksheet.Cells.Item($row,4) = $checkAD
if($ping){
$objWorksheet.Cells.Item($row,1) = $machine
$objWorksheet.Cells.Item($row,2) = "UP"
$iname = $ping.IPV4Address.IPAddressToString
$objWorksheet.Cells.Item($row,3) = $iname
$row++}
else {
$objWorksheet.Cells.Item($row,1) = $machine
$objWorksheet.Cells.Item($row,2) = "DOWN"
$row++}
}
Here's a start, using Test-Connection and Resolve-DnsName, assuming you have a list of hosts' IP and name separated by a space, with a carriage return between each host:
$Assets = #"
127.0.0.1 localhost
255.255.255.255 fakehost
"#
$FailedPing = #()
$NoDNS = #()
$Assets -split "`r" | %{
$ipaddress = ($_.split(' ')[0]).trim()
$hostName = ($_.split(' ')[1]).trim()
Write-Host "IP: $ipaddress HOST: $hostName "
Try {
Test-Connection -ComputerName $ipaddress -Count 2 -ErrorAction Stop | Out-Null
}Catch {
$FailedPing += [pscustomobject]#{IP=$ipaddress; HostName = $hostName}
}
Try {
Resolve-DnsName -Name $hostName -ErrorAction Stop | Out-Null
}Catch {
$NoDNS += [pscustomobject]#{HostName = $hostName;Problem = $Error[0].Exception}
}
}
$FailedPing | ft
$NoDNS | ft

Set Time limit for Get-process

Long story short, we are experiencing issues with some of our servers that cause crippling effects on them and I am looking for a way to monitor them, now I have a script that will check the RDP port to make sure that it is open and I am thinking that I want to use get-service and then I will return if it pulled any data or not.
Here is the issue I don't know how to limit the time it will wait for a response before returning false.
[bool](Get-process -ComputerName MYSERVER)
Although I like Ansgars answer with a time-limited job, I think a separate Runspace and async invocation fits this task better.
The major difference here being that a Runspace reuses the in-process thread pool, whereas the PSJob method launches a new process, with the overhead that that entails, such as OS/kernel resources spawning and managing a child process, serializing and deserializing data etc.
Something like this:
function Timeout-Statement {
param(
[scriptblock[]]$ScriptBlock,
[object[]]$ArgumentList,
[int]$Timeout
)
$Runspace = [runspacefactory]::CreateRunspace()
$Runspace.Open()
$PS = [powershell]::Create()
$PS.Runspace = $Runspace
$PS = $PS.AddScript($ScriptBlock)
foreach($Arg in $ArgumentList){
$PS = $PS.AddArgument($Arg)
}
$IAR = $PS.BeginInvoke()
if($IAR.AsyncWaitHandle.WaitOne($Timeout)){
$PS.EndInvoke($IAR)
}
return $false
}
Then use that to do:
$ScriptBlock = {
param($ComputerName)
Get-Process #PSBoundParameters
}
$Timeout = 2500 # 2 and a half seconds (2500 milliseconds)
Timeout-Statement $ScriptBlock -ArgumentList "mycomputer.fqdn" -Timeout $Timeout
You could run your check as a background job:
$sb = { Get-Process -ComputerName $args[0] }
$end = (Get-Date).AddSeconds(5)
$job = Start-Job -ScriptBlock $sb -ArgumentList 'MYSERVER'
do {
Start-Sleep 100
$finished = (Get-Job -Id $job.Id).State -eq 'Completed'
} until ($finished -or (Get-Date) -gt $end)
if (-not $finished) {
Stop-Job -Id $job.Id
}
Receive-Job $job.Id
Remove-Job $job.Id
This is a known issue: https://connect.microsoft.com/PowerShell/feedback/details/645165/add-timeout-parameter-to-get-wmiobject
There is a workaround provided Here : https://connect.microsoft.com/PowerShell/feedback/details/645165/add-timeout-parameter-to-get-wmiobject
Function Get-WmiCustom([string]$computername,[string]$namespace,[string]$class,[int]$timeout=15)
{
$ConnectionOptions = new-object System.Management.ConnectionOptions
$EnumerationOptions = new-object System.Management.EnumerationOptions
$timeoutseconds = new-timespan -seconds $timeout
$EnumerationOptions.set_timeout($timeoutseconds)
$assembledpath = "\\" + $computername + "\" + $namespace
#write-host $assembledpath -foregroundcolor yellow
$Scope = new-object System.Management.ManagementScope $assembledpath, $ConnectionOptions
$Scope.Connect()
$querystring = "SELECT * FROM " + $class
#write-host $querystring
$query = new-object System.Management.ObjectQuery $querystring
$searcher = new-object System.Management.ManagementObjectSearcher
$searcher.set_options($EnumerationOptions)
$searcher.Query = $querystring
$searcher.Scope = $Scope
trap { $_ } $result = $searcher.get()
return $result
}
You can call the function like this:
get-wmicustom -class Win32_Process -namespace "root\cimv2" -computername MYSERVER –timeout 1

Check for net.tcp binding in PowerShell

I am configuring a process that checks IIS settings on a Web Server for net.tcp bindings for a particual Web Site, and if it does not exist, create it. I have this chunk of code to check
$Websites = Get-ChildItem IIS:\Sites
foreach ($Site in $Websites) {
if ($Site.name -eq "LOSSI") {
$Binding = $Site.bindings
foreach ($bind in $Binding.collection) {
if ($bind -eq "net.tcp 443:*")
{
Write-Host $bind
}
}
}
}
But I never fall into the last conditional. I have validated by hand that the binding is set to
LOSSI
3
Started
D:\LOSSI
http *:63211: net.tcp 443:
I imagine I am doing something silly wrong, but I cannot figure it out. Is there an easier way to check a website for tcp binding?
function Test-TcpPort {
<#
.SYNOPSIS
Determine if computers have the specified ports open.
.EXAMPLE
PS C:\> Test-TcpPort -ComputerName web01,sql01,dc01 -Port 5985,5986,80,8080,443
.NOTE
Example function from PowerShell Deep Dives 2013.
#>
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[Alias("CN","Server","__Server","IPAddress")]
[string[]]$ComputerName = $env:COMPUTERNAME,
[int[]]$Port = 23,
[int]$Timeout = 5000
)
Process {
foreach ($computer in $ComputerName) {
foreach ($p in $port) {
Write-Verbose ("Checking port {0} on {1}" -f $computer, $p)
$tcpClient = New-Object System.Net.Sockets.TCPClient
$async = $tcpClient.BeginConnect($computer, $p, $null, $null)
$wait = $async.AsyncWaitHandle.WaitOne($TimeOut, $false)
if(-not $Wait) {
[PSCustomObject]#{
Computername = $ComputerName
Port = $P
State = 'Closed'
Notes = 'Connection timed out'
}
} else {
try {
$tcpClient.EndConnect($async)
[PSCustomObject]#{
Computername = $computer
Port = $p
State = 'Open'
Notes = $null
}
} catch {
[PSCustomObject]#{
Computername = $computer
Port = $p
State = 'Closed'
Notes = ("{0}" -f $_.Exception.Message)
}
}
}
}
}
}
}
Microsoft reference script for check port
add this function in
for powershell 64 bit
C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1
for powershell 32 bit
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\profile.ps1
then open powershell use this
Test-TCPPort google.com -Port 80
output :
True

Powershell Timeout After two Seconds

I'm new to powershell. I read some lines on www.powershell.com. Now I need your help to solve a problem. I want to read the UUID from clients in the Network. Therefore I created a document "pcs.txt" where all PCs are stored.
$pc = Get-Content pcs.txt #Read content of file
$cred = Get-Credential “domain\user”
for ($i=0; $i -lt $pc.length; $i++) {
$Result=test-connection -ComputerName $pc[$i] -Count 1 -Quiet
If ($Result -eq 'True')
{
$uuid = (Get-WmiObject Win32_ComputerSystemProduct -ComputerName $pc[$i] -Credential $cred).UUID
$Ausgabe=$pc[$i] + ';'+$uuid
$Ausgabe
}
else
{
$Ausgabe=$pc[$i] + '; UUID nicht erhalten'
$Ausgabe
}
}
First I test if the ping works. When the ping works I try to get the uuid.
Sometimes I don't get the uuid even if the ping worked. So I would like to code a timeout, which say -> go to next pc when you don't have the uuid after 2 seconds.
Can you help me please?
Alas, there is no timeout parameter for Get-WmiObject commandlet. There is a feature request in MS Connect, but it is from 2011 and still open.
A workaround, which I haven't tested is available by using System.Management. I'll copy-and-paste it here in case the link goes dead. (And I hate SO answers that only contain links to resouces that may or may not exist...)
Function Get-WmiCustom([string]$computername,[string]$namespace,[string]$class,[int]$timeout=15){
$ConnectionOptions = new-object System.Management.ConnectionOptions
$EnumerationOptions = new-object System.Management.EnumerationOptions
$timeoutseconds = new-timespan -seconds $timeout
$EnumerationOptions.set_timeout($timeoutseconds)
$assembledpath = "\\" + $computername + "\" + $namespace
#write-host $assembledpath -foregroundcolor yellow
$Scope = new-object System.Management.ManagementScope $assembledpath, $ConnectionOptions
$Scope.Connect()
$querystring = "SELECT * FROM " + $class
#write-host $querystring
$query = new-object System.Management.ObjectQuery $querystring
$searcher = new-object System.Management.ManagementObjectSearcher
$searcher.set_options($EnumerationOptions)
$searcher.Query = $querystring
$searcher.Scope = $Scope
trap { $_ } $result = $searcher.get()
return $result
}
I found a good workaround!
http://theolddogscriptingblog.wordpress.com/2012/05/11/wmi-hangs-and-how-to-avoid-them/
Here my working code:
$pc = Get-Content pcs.txt #FILE FROM THE HARDDISK
$cred = Get-Credential “DOMAIN\USER” #
for ($i=0; $i -lt $pc.length; $i++)
{
$Result=test-connection -ComputerName $pc[$i] -Count 1 -Quiet
If ($Result -eq 'True')
{
$WMIJob = Get-WmiObject Win32_ComputerSystemProduct -ComputerName $pc[$i] -Credential $cred -AsJob
$Timeout=Wait-Job -ID $WMIJob.ID -Timeout 1 # the Job times out after 1 seconds.
$uuid = Receive-Job $WMIJob.ID
if ($uuid -ne $null)
{
$Wert =$uuid.UUID
$Ausgabe=$pc[$i] + ';'+$Wert
$Ausgabe
}
else
{
<#$b = $error | select Exception
$E = $b -split (:)
$x = $E[1]
$Error.Clear() #>
$Ausgabe=$pc[$i] + '; got no uuid'
$Ausgabe
}
}
else
{
$Ausgabe='PC not reached through ping.'
$Ausgabe
}
}
I hope I can help somebody with that