I wrote a Powershell script that will perform Ping, RDP(3389), Remote Registry and WMI connectivity to a remote computer. Below is the script that I have come up with. Now I would like to get the output in a short format such as:
PING : SUCCESS
RDP : FAIL
Remote Registry : FAIL
WMI : SUCCESS
Remote Registry check has FAILED.
RDP check has FAILED.
PING check SUCCEEDED
WMI check SUCCEEDED
I am looking for help as I am new to Powershell scripting. Thank you in advance!!
Write-Host `n
$inputfromuser = Read-Host "Enter Server Name"
If($inputfromuser -like "")
{
Write-Host "User Input cannot be blank. Please enter the server name"
Write-Host `n
}
else
{
Write-Host `n
Write-Host -ForegroundColor Yellow "CHECKING PING CONNECTIVITY TO SERVER $inputfromuser"
Test-Connection -ComputerName $inputfromuser -Quiet -Count 1
Write-Host `n
Write-Host -ForegroundColor Yellow "CHECKING RDP PORT 3389 CONNECTIVITY ...."
Test-NetConnection -ComputerName $inputfromuser -CommonTCPPort RDP -InformationLevel Quiet
Write-Host `n
Write-Host -ForegroundColor Yellow "CHECKING REMOTE REGISTRY CONNECTIVITY ...."
$regkey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,$inputfromuser)
$ref = $regkey.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall")
If (!$ref) {
Write-Host -ForegroundColor Red "REMOTE REGISTRY CHECK FAILED"
}
Else {
Write-Host -ForegroundColor Green "REMOTE REGISTRY CHECK SUCCESS"
}
Write-Host `n
Write-Host -ForegroundColor Yello "CHECKING REMOTE WMI CONNECTIVITY ...."
$wmi = GWMI -Query "Select * from Win32_PingStatus where Address = '$inputfromuser'"
If (!$wmi) {
Write-Host -ForegroundColor Red "REMOTE WMI CHECK FAILED"
}
Else {
Write-Host -ForegroundColor Green "REMOTE WMI CHECK SUCCESS"
}
Write-Host `n
}
I'd recommend separating tests from output creation. Assign the results of your checks to separate variables:
$ping = Test-Connection ...
$rdp = Test-NetConnection ...
$regkey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $inputfromuser)
$ref = $regkey.OpenSubKey("...")
$wmi = Get-WmiObject -Query "..."
create 2 hashtables:
$state_noun = #{
$true = 'SUCCESS'
$false = 'FAIL'
}
$state_verb = #{
$true = 'SUCCEEDED'
$false = 'FAILED'
}
and create the output with a here-string:
$result = #"
PING : $($state_noun[$ping])
RDP : $($state_noun[$rdp])
Remote Registry : $($state_noun[[bool]$ref])
WMI : $($state_noun[[bool]$wmi])
Remote Registry check has $($state_verb[[bool]$ref]).
RDP check has $($state_verb[$rdp]).
PING check $($state_verb[$ping])
WMI check $($state_verb[[bool]$wmi])
"#
Write-Host $result
If you must have highlighted/colored values in your output, use a custom output function like this:
function Write-Result {
[CmdletBinding()]
Param(
[Parameter()][string]$text,
[Parameter()][bool]$value
)
Write-Host $text -NoNewline
if ($value) {
Write-Host $value -NoNewline -ForegroundColor Green
} else {
Write-Host $value -NoNewline -ForegroundColor Red
}
Write-Host '.'
}
Write-Result 'PING : ' $state_noun[$ping]
...
Write-Result 'Remote Registry check has ' $state_verb[[bool]$ref]
...
Related
This is the script that changes the configuration of DNS properties like setting the IP address, Default Gateway, and DNS server address which can be found at Control Panel -> Network and sharing center -> select adapter -> Properties -> Internet Protocol Version 4(TCP/IPv4).
This script is running perfectly on windows 7 32-bit and windows 10 32-bit systems but for some reason, it's not working on windows 7 64 bit. Whenever I try to change the IP address it throws the error code 97 i.e. Interface not configurable. If I use the function on the adapter directly in PowerShell command line like $adapter = (get-wmiobject win32_networkadapterconfiguration | where-object {$_.index -eq 7})
$adapter.EnableStatic("192.168.1.50", "255.255.255.0")
it's working on the Powershell command-line user interface. I can't figure out why or how is it happening?
UPDATE:
I tried to debug the code and I found that for some reason I can't fetch AdapterIndex from hash_Table network_info like
$network_info = Get-IPAdapterInformation
[string]$AdapterName = $network_info.AdapterName
[string]$AdapterInterfaceIndex = $network_info.AdapterInterfaceIndex
[string]$AdapterIndex = $network_info.AdapterIndex
cls
#function to get Adapter Info based on Mac-Address
function Get-IPAdapterInformation{
# [CmdletBinding()]
$AdapterInfo = #{}
# $MyMacAddress = "00:15:5D:00:A3:07"
$MyMacAddress = Read-Host "Enter Mac Address of Adapter"
$MyMacAddress = $MyMacAddress.Trim()
Try { $IPconfigset = Get-WmiObject Win32_NetworkAdapterConfiguration -Namespace "root\CIMv2" -ErrorAction:Stop | ? {$_.IPEnabled -and ($_.MACAddress -ne $null)} } Catch { return $IPs }
foreach ($ip in $IPconfigset) {
if($ip.MACAddress -eq $MyMacAddress){
$i = New-Object PSObject | Select-Object Index, InterfaceIndex, IPAddress, Subnet, Name, DeviceName, MACAddress, DNSSearchOrder, Gateway, Status
$i.Index = $ip.Index
$i.InterfaceIndex = $ip.InterfaceIndex
$i.IPAddress = $ip.IPAddress[0]
$i.Subnet = $ip.IPSubnet[0]
$i.DeviceName = $ip.Description
$i.MACAddress = $ip.MACAddress
$i.DNSSearchOrder = $ip.DNSServerSearchOrder
$i.Gateway = $ip.DefaultIPGateway
$i.Name = (Get-WmiObject win32_networkadapter -ErrorAction:SilentlyContinue | ? {$_.Name -eq $i.DeviceName}).netconnectionid
$i.Status = (Get-WmiObject win32_networkadapter -ErrorAction:SilentlyContinue | ? {$_.Name -eq $i.DeviceName}).NetConnectionStatus
$AdapterInfo.add('AdapterName', $i.Name)
$AdapterInfo.add('AdapterInterfaceDescription', $i.DeviceName)
$AdapterInfo.add('AdapterInterfaceIndex', $i.InterfaceIndex)
$AdapterInfo.add('AdapterIndex', $i.Index)
}
}
if($AdapterInfo -ne $null){
Write-Host "Adapter Found!" -ForegroundColor Green
Write-Host "Adapter Name:"$AdapterInfo.AdapterName -ForegroundColor Green
Write-Host "Adapter InterfaceIndex:"$AdapterInfo.AdapterInterfaceIndex -ForegroundColor Green
Write-Host "Adapter Interface Description:"$AdapterInfo.AdapterInterfaceDescription -ForegroundColor Green
Write-Host "Adapter Index:"$AdapterInfo.AdapterIndex -ForegroundColor Green
}else{
Write-Host "No Adapter found with given MacAddress" -ForegroundColor Ref
}
return $AdapterInfo
}
#====================================================================
# STEP #2: SETUP NETWORK
#====================================================================
Write-Host "Available Network Adapters on this Device:" -ForegroundColor Green
Get-WmiObject Win32_networkAdapter | ?{$_.MACAddress -ne $null} | Select NetConnectionID, Name, MACAddress, Description, InterfaceIndex, NetConnectionStatus
$network_info = Get-IPAdapterInformation
#$network_info
[string]$AdapterName = $network_info.AdapterName
[string]$AdapterInterfaceIndex = $network_info.AdapterInterfaceIndex
[string]$AdapterIndex = $network_info.AdapterIndex
#Returns StatusCode Description based on given status code
function Get-StatusCodeDescripton($StatusCode){
Switch($StatusCode){
0{
return "Successful completion, no reboot required"
}1{
return "Successful completion, reboot required"
}64{
return "Method not supported on this platform"
}65{
return "Unknown failure"
}66{
return "Invalid subnet mask"
}67{
return "An error occurred while processing an Instance that was returned"
}68{
return "Invalid input parameter"
}69{
return "More than 5 gateways specified"
}70{
return "Invalid IP address"
}71{
return "Invalid gateway IP address"
}72{
return "An error occurred while accessing the Registry for the requested information"
}73{
return "Invalid domain name"
}74{
return "Invalid host name"
}75{
return "No primary/secondary WINS server defined"
}76{
return "Invalid file"
}77{
return "Invalid system path"
}78{
return "File copy failed"
}79{
return "Invalid security parameter"
}80{
return "Unable to configure TCP/IP service"
}81{
return "Unable to configure DHCP service"
}82{
return "Unable to renew DHCP lease"
}83{
return "Unable to release DHCP lease"
}84{
return "IP not enabled on adapter"
}85{
return "IPX not enabled on adapter"
}86{
return "Frame/network number bounds error"
}87{
return "Invalid frame type"
}88{
return "Invalid network number"
}89{
return "Duplicate network number"
}90{
return "Parameter out of bounds"
}91{
return "Access denied"
}92{
return "Out of memory"
}93{
return "Already exists"
}94{
return "Path, file or object not found"
}95{
return "Unable to notify service"
}96{
return "Unable to notify DNS service"
}97{
return "Interface not configurable"
}98{
return "Not all DHCP leases could be released/renewed"
}100{
return "DHCP not enabled on adapter"
}101{
return "Some error occured!"
}default{
return "Some Unknown error occurred!"
}
}
}
#Set IP address(Input: IPAddrss, DefaultGateway, SubnetMask(Optional))
function Set-IPAddress{
[CmdletBinding()]
Param(
#IP Address
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[String]$IPAddress,
#Default Gateway
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=1)]
[String]$DefaultGateway
)
$IPAddress
$SubNetMask = Read-Host "Enter Subnet Mask[Default 255.255.255.0]"
if(-not $SubNetMask){
$SubNetMask ="255.255.255.0"
}
$SubNetMask
$adapter = (get-wmiobject win32_networkadapterconfiguration -ErrorAction:SilentlyContinue | where-object {$_.index -eq $AdapterIndex})
$IPandSubnetMaskResult = $adapter.EnableStatic($IPAddress, $SubNetMask) #IPAddress, Subnet Mask
$IPandSubnetMaskResultCode = $IPandSubnetMaskResult.ReturnValue
$IPandSubnetMaskResultCode
$IPandSubnetMaskResultDesciption = Get-StatusCodeDescripton($IPandSubnetMaskResultCode)
if(($IPandSubnetMaskResultCode -eq 0) -or ($IPandSubnetMaskResultCode -eq 1)){
Write-Host $IPandSubnetMaskResultDesciption -ForegroundColor Green
Write-Host "[SUCCESS] Changed Static IP Address to: $($IPAddress)." -ForegroundColor Green
}else{
Write-Host $IPandSubnetMaskResultDesciption -ForegroundColor Red
}
$GatewayResult = $adapter.SetGateways($DefaultGateway)
$GatewayResultCode = $GatewayResult.ReturnValue
$GatewayResultDescription = Get-StatusCodeDescripton($GatewayResultCode)
if(($GatewayResultCode -eq 0) -or ($GatewayResultCode -eq 1)){
Write-Host $GatewayResultDescription -ForegroundColor Green
Write-Host "[SUCCESS] Changed Default GAteway to: $($DefaultGateway)." -ForegroundColor Green
}else{
Write-Host $GatewayResultDescription -ForegroundColor Red
Write-Host "An Error occurred!" -ForegroundColor Red
}
Sleep -Seconds 4 #sometimes setting instantly IP address gives error 67.
}
#Set DNS Server Address(Input:PrimaryDNSAddress, SecondaryDNSAddress(Optional))
function Set-DNSServerAdddress{
[CmdletBinding()]
Param(
#Primary DNS Server Address
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[String]$PrimaryDNSAddress
)
$SecondaryDNSAddress = Read-Host "Enter Secondary DNS Address[Optional]"
$adapter = (get-wmiobject win32_networkadapterconfiguration -ErrorAction:SilentlyContinue | where-object {$_.index -eq $AdapterIndex})
if($SecondaryDNSAddress){
$SetDNSServerAddressResult = $adapter.SetDNSServerSearchOrder(#($PrimaryDNSAddress, $SecondaryDNSAddress))
}else{
$SetDNSServerAddressResult = $adapter.SetDNSServerSearchOrder(#($PrimaryDNSAddress))
}
$SetDNSServerAddressResultCode = $SetDNSServerAddressResult.ReturnValue
$SetDNSServerAddressResultDescription = Get-StatusCodeDescripton($SetDNSServerAddressResult)
if(($SetDNSServerAddressResultCode -eq 0) -or ($SetDNSServerAddressResultCode -eq 1)){
Write-Host $SetDNSServerAddressResultDescription -ForegroundColor Green
Write-Host "[SUCCESS] Set DNS Servers to: $($PrimaryDNSAddress), $($SecondaryDNSAddress)." -ForegroundColor Green
}else{
Write-Host $GatewayResultDescription -ForegroundColor Red
Write-Host "An Error occurred!" -ForegroundColor Red
}
Sleep -Seconds 4
}
function Set-DNSSererAddressAutomatically{
$userInput = Read-Host "Do you want to set DNS Server Address Automatically? [y]Yes [n]No[Default NO]"
if($userInput -eq "y" -or $userInput -eq "yes"){
$adapter = (get-wmiobject win32_networkadapterconfiguration -ErrorAction:SilentlyContinue | where-object {$_.index -eq $AdapterIndex})
$SetDNSServerAddressAutomaticallyResult = $adapter.SetDNSServerSearchOrder()
$SetDNSServerAddressAutomaticallyResultCode = $SetDNSServerAddressAutomaticallyResult.ReturnValue
$SetDNSServerAddressAutomaticallyResultDescription = Get-StatusCodeDescripton($SetDNSServerAddressAutomaticallyResultCode)
if(($SetDNSServerAddressAutomaticallyResultCode -eq 0) -or ($SetDNSServerAddressAutomaticallyResultCode -eq 1)){
Write-Host $SetDNSServerAddressAutomaticallyResultDescription -ForegroundColor Green
Write-Host "[SUCCESS] Set DNS Servers Automatically." -ForegroundColor Green
}else{
Write-Host $SetDNSServerAddressAutomaticallyResultDescription -ForegroundColor Red
Write-Host "An Error occurred!" -ForegroundColor Red
}
}else{
Write-Warning "You selected NO"
}
Sleep -Seconds 4
}
function Set-IPAddressAutomatically{
$userInput = Read-Host "Set IP Automatically? [y]Yes [n]No[Default NO]"
if($userInput -eq "y" -or $userInput -eq "yes"){
$adapter = (get-wmiobject win32_networkadapterconfiguration -ErrorAction:SilentlyContinue | where-object {$_.index -eq $AdapterIndex})
$SetIPAddressAutomaticallyResult = $adapter.EnableDHCP()
$SetIPAddressAutomaticallyResultCode = $SetIPAddressAutomaticallyResult.ReturnValue
$SetIPAddressAutomaticallyResultDescription = Get-StatusCodeDescripton($SetIPAddressAutomaticallyResultCode)
if(($SetIPAddressAutomaticallyResultCode -eq 0) -or ($SetIPAddressAutomaticallyResultCode -eq 1)){
Write-Host $SetIPAddressAutomaticallyResultDescription -ForegroundColor Green
Write-Host "[SUCCESS] Set IP Addresss Automatically." -ForegroundColor Green
}else{
Write-Host $SetIPAddressAutomaticallyResultDescription -ForegroundColor Red
Write-Host "An Error occurred!" -ForegroundColor Red
}
}else{
Write-Warning "You selected NO"
}
Sleep -Seconds 4
}
#Set-IPAddress #working
#Set-DNSServerAdddress #not working with2nd DNS Server Address
#Set-DNSSererAddressAutomatically # working
#Set-IPAddressAutomatically #working
$choices = "Select Operation:
0. Print Choices
1. Set IP Address and Default Gateway
2. Set DNS Server Address
3. Set IP Address Automatically
4. Set DNS Server Address Automatically
t. exit/terminate
"
$status = $true
while($status){
$choice = Read-Host "Select choice: $choices"
$choice
switch($choice){
0{
Write-Host " ==> Print choices: $choices" -ForeGround Green
break
}
1{
Write-Host " ==> Set IP Address and Default Gateway" -ForeGround Green
Set-IPAddress
break
}
2{
Write-Host " ==> Set DNS Server Address" -ForeGround Green
Set-DNSServerAdddress
break
}
3{
Write-Host " ==> Set IP Address Automatically" -ForeGround Green
Set-IPAddressAutomatically
break
}
4{
Write-Host " ==> Set DNS Server Address Automatically"
Set-DNSSererAddressAutomatically
break
}
t{
Write-Host " ==> Exit" -ForeGround Green
$status = $false
}
}
}
#Index : 7
#InterfaceIndex : 11
#IPAddress : 192.168.234.197
#Subnet : 255.255.240.0
#Name : Local Area Connection
#DeviceName : Microsoft Virtual Machine Bus Network Adapter
#MACAddress : 00:15:5D:00:A3:07
#DNSSearchOrder : {192.168.224.1}
#Gateway : {192.168.224.1}
#Status : 2
I did go ahead and run the entire script as-is up to where you were having trouble at $network_info.AdapterIndex on a machine running Windows 7 64-bit, and I'm able to pull the $AdapterIndex without issues, so it may just be that VM?
I would also recommend feeding $AdapterIndex as a parameter to your other functions instead of basically using it as a global variable.
For the issue of not being able to access an element of a hashtable, I believe the problem is probably earlier in your script. For example, you're not really checking if $network_info has any data. My guess would be something like your WMI query on that VM doesn't actually return a valid object. Try out something like this on the 64-bit win7 VM - basically just removing some of the function structures and -erroraction SilentlyContinue flags:
$MyMacAddress = "00:00:00:3C:7A:00" # yours here
$MatchingAdapter = Get-WmiObject Win32_NetworkAdapterConfiguration |
Where {$_.IPEnabled -and ($_.MACAddress -eq $MyMacAddress )}
# double-check you actually found an adapter via MAC
if (!$MatchingAdapter) {throw "No adapter found with MAC address $MyMacAddress";break}
$AdapterInfo = #{
AdapterName = (
Get-WmiObject -Query "SELECT netconnectionID FROM win32_networkadapter WHERE Name = '$($MatchingAdapter.Description)'"
).netconnectionid
AdapterInterfaceDescription = $MatchingAdapter.Description
AdapterInterfaceIndex = $MatchingAdapter.InterfaceIndex
AdapterIndex = $MatchingAdapter.Index
}
[PSCustomObject]$AdapterInfo | fl
If that returns reasonable values, then this should work too:
$Adapter = Get-WMIObject -Query "SELECT * FROM win32_networkadapterconfiguration WHERE index = '$($MatchingAdapter.Index)'"
$IPandSubnetMaskResult = $adapter.EnableStatic($IPAddress, $SubNetMask)
We are in the process of migrating user mailboxes from on-prem exchange to office 365. Since we are only doing few users at a time, our requirements were to sync local outlook client signatures into office 365 OWA portal. So user sees the same signature on their OWA portal.
Has anyone done this?
I have figured it out. So I have created a script to help our migration team to upload local outlook client signature to office 365.
You need to have admin access to user PC and exchange online admin privileges such as Global Administrator.
Here is the code:
write-host "`n`n`n`n"
#initializing variables
$username = $null
$computer = $null
$path = $null
$number = $null
$i = 0
$select = $null
$signs = $null
$chkerr = $false
$session = $null
#Run a continous loop
do {
#if powershell is not connected to office 365 then run the connection code below
if ($session.State -ne "opened") {
Write-Host "`nChecking connection to Office 365: " -NoNewline
Write-Host "Inactive!" -ForegroundColor white -BackgroundColor red
Write-Host "`nConnecting to Office 365 account...`n"
#Get user office 365 credentials
$UserCredential = Get-Credential
#create session
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
#start the session to office 365
Import-PSSession $Session
Sleep 4
}
#if the session to 365 is success then run the code below
if ($?) {
Write-Host "`nChecking connection to Office 365: " -NoNewline
Write-Host "Active!" -ForegroundColor Black -BackgroundColor green
#Start a loop to prompt for username and machinename
do {
#this variable is used below and set as false if there is an error. Also, shows a message that user need to re-enter the information
$chkerr = $false
if ($chkerr) {write-host "`nPlease try again..." -BackgroundColor yellow -ForegroundColor black}
#store username and machine name
$username = Read-Host "`n`nPlease enter user name"
$computer = Read-Host "Please enter computer name"
#if machine is not pingable then show an error
if (!(Test-Connection $computer -Count 1) ) {Write-Host "`nError: Computer is offline or name is incorrect" -ForegroundColor white -BackgroundColor red; $chkerr = $true}
else {
#if machine is pingable then check if signature direcotry exists
if (!(Test-Path "\\$computer\c$\Users\$username\AppData\Roaming\Microsoft\Signatures\")) { Write-Host "`nError: Outlook signature directory does not exists `nOR `nUsername is incorrect!" -ForegroundColor white -BackgroundColor red;$chkerr = $true}
}
#show error msg if username or machine name is left blank
if ($username -eq $null -or !$username -or $computer -eq $null -OR !$computer) {Write-Host "`nError: Username or computer name cannot be left empty" -ForegroundColor white -BackgroundColor red;$chkerr = $true }
#repeatedly ask for username and machine name until user gets it right or moves on to next username and machine name
} while ($chkerr)
#set the path to signature directory
$path = "\\$computer\c$\Users\$username\AppData\Roaming\Microsoft\Signatures"
#get a list of signature files and store them in a variable
$number = Get-ChildItem "$path\*.htm"
#check if there are any signature files at all
if ($number -or $number -ne $null) {
#start a loop
do {
#if there are multiple signature files found then show them on screen
Write-Host "`nSelect one for following file:`n"
for ([int]$i=0;$i -lt $number.count; $i++) {
Write-Host ("$i" +' --> ' + $number[$i].name)
}
#if there is more than one signature file then prompt user to select one
if ($number.count -gt 1) {
$select = Read-Host "`nPlease enter your selection"
#show error if user enters a number that is of selection
if ([int]$select+1 -gt [int]$number.Count) {Write-Host "`nError: Please enter a valid selections!" -ForegroundColor white -BackgroundColor red}
} else {
#if only one signature file is found then do not prompt and select that one file as default
$select = "0"
Write-Host "`nOnly one file found, selecting default file -->" $number[$select].name -ForegroundColor black -BackgroundColor yellow
}
#repeat the loop until user selects atleast one signature file
} while ([int]$select+1 -gt [int]$number.Count)
#show the selected signature file
Write-Host "You have selected following signature file:" $number[$select].fullname
sleep 3
#grab the html file and store it into a variable
Write-Host "`nImporting signatures into powershell"
$signs = Get-Content $number[$select].fullname
#show error if the signature import fails
if (!$?) {Write-Host "`nError: Unable to import signature into powershell!" -ForegroundColor white -BackgroundColor red}
else {
Write-Host "`nSuccess!" -ForegroundColor Black -BackgroundColor green
Write-Host "`nImporting signatures to Office 365 account of $username"
#import the signature into users OWA and set it to be used during replies, forwards and message creations.
Get-Mailbox $username | Set-MailboxMessageConfiguration -SignatureHtml $signs -AutoAddSignature:$true -AutoAddSignatureOnReply:$true -AutoAddSignatureOnMobile:$true
if (!$?) {Write-Host "`nError: Unable to import signature into Office 365 account!" -ForegroundColor white -BackgroundColor red}
else {Write-Host "`nSuccess!" -ForegroundColor Black -BackgroundColor green}
}
}
else {
#show error if no signature files are found
Write-Host "`nError: No signature files found!" -ForegroundColor white -BackgroundColor red
}
}
else {
# show error if we are unable to connect to office 365 account.
Write-Host "`nError: Connection to office 365 is required for this script to work" -ForegroundColor white -BackgroundColor red
}
} while ($true)
Successful test of Output:
Making connection:
After successfull connection:
After entering username and password:
After making the selection:
OWA view:
Error checking against user input:
Entering wrong office 365 credentials:
Entering correct computer name but wrong username:
Entering correct username but wrong computer name:
Entering wrong selecting that is out of the provided set of options:
You can also modify the script to grab input from an excel sheet.
Is there a script that can log out my disconnected RDP session from any server? This is causing a lot of pain and constant ad account lockouts.
Any help would be awesome.
I have got the answer and I am writing this answer to help someone in need as I had to figure this out myself. I created a script using online resources to find out disconnected RDP sessions on all Windows Server in my AD environment. I run a query on each Windows Server and create a CSV formatted list, I then use that list to log out my ID from those servers, so I don't have any disconnected sessions.
I did this to make sure my AD account doesn't get locked out due to some disconnected RDP sessions when its time to change my password.
You are free to modify this script as per your need.
Script Code is below:
param (
#get current logged on username
[string]$UserName = $env:USERNAME
)
# Import the Active Directory module for the Get-ADComputer CmdLet
Import-Module ActiveDirectory
# Query Active Directory for enabled windows servers computer accounts and sort by name
$Servers = Get-ADComputer -Filter {(OperatingSystem -like "*windows*server*") -and (Enabled -eq "True")} | Sort Name
# Initiating variables
$SessionList = $NULL
$queryResults = $NULL
$SError = $null
$SDown = $null
$z = 0
# Get total number of servers
$count = $Servers.count
# Start looping through each server at a time
ForEach ($Server in $Servers) {
# initiate counter for showing progress
$z = $z + 1
$ServerName = $Server.Name
# Start writing progress
Write-Progress -Activity "Processing Server: $z out of $count servers." -Status " Progress" -PercentComplete ($z/$Servers.count*100)
# check if server is pingable before running the query on the server
if (Test-Connection $Server.Name -Count 1 -Quiet) {
Write-Host "`n`n$ServerName is online!" -BackgroundColor Green -ForegroundColor Black
Write-Host ("`nQuerying Server: `"$ServerName`" for disconnected sessions under UserName: `"" + $UserName.ToUpper() + "`"...") -BackgroundColor Gray -ForegroundColor Black
# Store results in array
[array]$queryResults += (
# Query server for specific username
query user $UserName /server:$ServerName |
foreach {
# Look for lines with Disc string to filter out active sessions
if ($_ -match "Disc") {
# format the output in CSV by replacing more than 2 spaces with a comman
write-output ("`n$ServerName," + (($_.trim() -replace ' {2,}', ',')))
}
}
)
}
# If server is not pingable show error message
else {
# Make list of server that are down.
[array]$SDown += ($ServerName)
Write-Host "`nError: Unable to connect to $ServerName!" -BackgroundColor red -ForegroundColor white
Write-Host "Either the $ServerName is down or check for firewall settings on server $ServerName!" -BackgroundColor Yellow -ForegroundColor black
}
}
# If there are some non pingable server then display the list
if ($SDown -ne $null -and $SDown) {
Write-Host "`nScript was unable to connect to the following server:" -ForegroundColor White -BackgroundColor Red
$SDown
}
# Check if any disconnected session are stored in the array
if ($queryResults -ne $null -and $queryResults) {
# Convert the CSV fromat to table format with headers
$QueryResultsCSV = $queryResults | ConvertFrom-Csv -Delimiter "," -Header "ServerName","UserName","SessionID","CurrentState","IdealTime","LogonTime"
# Show the results on console
$QueryResultsCSV |ft -AutoSize
# Go through each Disconnected session stored in the array
$QueryResultsCSV | foreach {
# Grabb session ID and ServerName
$Sessionl = $_.SessionID
$Serverl = $_.ServerName
# Show message on the console
Write-Host "`nLogging off"$_.username"from $serverl..." -ForegroundColor black -BackgroundColor Gray
sleep 2
# Logout user using session ID
logoff $Sessionl /server:$Serverl /v
}
}
else {
# if array is empty display message that no session were found
Write-Host `n`n`n`n("*" * $LineSize)
Write-Host "You are all good! No ghost sessions found!" -BackgroundColor Green -ForegroundColor Black
Write-Host ("*" * $LineSize)
}
# Pause at the end so you can capture the output
$null = Read-Host "`n`nScript execution finished, press enter to exit!"
Screenshots:
When the script is running on through all server, shows you online and offline servers:
List of servers that Script was unable to connect:
The script lists the servers where it found disconnected RDP sessions.
When script start to log your disconnected sessions off and it pauses at the end.
Thank you for your sample code. I have created a simplified code to logoff all disconnected users in the same server
$hostname = hostname
if (Test-Connection -ComputerName $hostname -Quiet -Count 1){
$result = query session /server:$hostname
$rows = $result -split "`n"
foreach ($row in $rows) {
if ($row -NotMatch "services|console" -and $row -match "Disc") {
$sessionusername = $row.Substring(19,20).Trim()
$sessionid = $row.Substring(39,9).Trim()
Write-Output "Logging Off RDP Disconnected Sessions User $sessionusername"#, $session[2], $session[3]"
logoff $sessionid /server:$hostname
}
}
}
I have 2 sections of PowerShell code that exit the script on failure. After thinking about it I realized it would make more sense to pause on a failure and allow the admin time to remediate... then when the any key is paused, retry the same line in the CSV. Here's how it looks now:
#check tools status first
Write-Host ""
Write-Host "Checking VMware Tools Status before proceeding." -foreground green
Write-Host ""
foreach ($item in $vmlist) {
$vmname = $item.vmname
$ToolsStatus = (Get-VM $vmname).extensiondata.Guest.ToolsStatus -eq "toolsNotRunning"
if ($ToolsStatus -eq $true) {
Write-Host ""
Write-Host "Tools is not installed or running on $vmname. Remediate on guest and restart the script" -foreground Yellow
Write-Host "Script will continue to exit until tools is running on $vmname" -foreground yellow
Write-Host ""
exit
} else {
Write-Host ""
Write-Host "Tools running on all VMs, script will continue" -foreground green
Write-Host ""
}
}
I know how to put the pause in $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown'), but I have no idea to do the loop so it retries.
I'm using similar code elsewhere to validate that VMs are powered up so this will work in both sections.
EDIT: Here's the re-worked script. Would this work?
foreach ($item in $vmlist) {
$vmname = $item.vmname
do {
$ToolsStatus = (Get-VM $vmname).extensiondata.Guest.ToolsStatus -eq "toolsNotRunning"
if ($ToolsStatus) {
Write-Host ""
Write-Host "Tools is not installed or running on $vmname." -Foreground yellow
Write-Host "Remediate VMware tools on $vmname and"
Write-host "Press any key to retry..."
$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
}
} until ($ToolsStatus -eq "PoweredOn")
Write-Host "Tools running on $vmname, script will continue" -Foreground green
}
Add a nested do..while loop like this:
foreach ($item in $vmlist) {
$vmname = $item.vmname
do {
$ToolsMissing = (Get-VM $vmname).extensiondata.Guest.ToolsStatus -eq "toolsNotRunning"
if ($ToolsMissing) {
Write-Host "Tools is not installed or ..." -Foreground yellow
$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
}
} while ($ToolsMissing)
}
Write-Host "Tools running on all VMs, script will continue" -Foreground green
I am very new to coding so I know very little.
I am writing my first code which is a ping. It can ping any workstation ID that you put in it. I would like that when it pings, the reply would be green and request timed out would be red.
I just want to test it out and learn from it. So far I have this:
$Search = Read-Host "Enter Workstation ID"
$Reply = ping -t $Search
if ($Reply -like "Request Timed Out.") {
Write-Host $Reply -ForegroundColor Red
}
But that is not working.
If you look at the usage message from ping.exe, you'll see that the -t switch makes ping.exe continue pinging the host until interrupted by Ctrl+C or Ctrl+Break.
That's why it seems like it's "doing nothing".
I would probably go for the Test-Connection cmdlet, rather than ping.exe:
$Hostname = Read-Host "please enter the hostname..."
if(Test-Connection -ComputerName $Hostname -Quiet)
{
Write-Host "Ping succeeded!" -ForegroundColor Green
}
else
{
Write-Host "Ping failed!" -ForegroundColor Red
}
It doesn't have a -t parameter, but you can provide a ridiculously high value to the -Count parameter, and make due with that (with a second in between each request, [int]::MaxValue gives you 2^31 seconds, or 68 years worth of pinging):
Test-Connection $Hostname -Count ([int]::MaxValue)
If you sincerely want the -t switch, you can't rely on assignment to a variable, since PowerShell will wait for ping.exe to return (which, intentionally, never happens).
You can however pipe the standard output from ping.exe, and PowerShell's asynchronous runtime will keep them coming for as long as you like:
function Keep-Pinging
{
param([string]$Hostname)
ping.exe -t $Hostname |ForEach-Object {
$Color = if($_ -like "Request timed out*") {
"Red"
} elseif($_ -like "Reply from*") {
"Green"
} else {
"Gray"
}
Write-Host $_ -ForegroundColor $Color
}
}