Powershell integration with Office365 - powershell

I would like some comments on the integration code that I am developing... trying to integrate Office365 to Solarwinds:
import-Module Office365Alerts
$Username = 'XXXXX#XXX.XXX'
$Password = 'XXXXXXXXXXXXXXXX'
$credential = New-Object -TypeName pscredential -ArgumentList $Username, ($Password | ConvertTo-SecureString -AsPlainText -Force) -ErrorAction Stop
$alerts = Get-Office365ServiceHealth -Credential $credential -ErrorAction Stop | Select-Object -Property * | Where-Object Service -like '*Exchange*'
foreach($a in $alerts){
[regex]$regex = '\bCurrent status:\s?.*\s'
$Mess = $a.LatestMessage
if($Mess -match $regex){
foreach($m in $mess){
Write-Host "Message:Title: $($a.Title)"
Write-Host "Message:Impact: $($a.UserImpact)"
Write-Host "Message:Start Time: $($a.StartTime)"
Write-Host "Message:Last Update: $($a.LastUpdate)"
Write-Host "Message: $($Matches.Values)"
}
Write-Host "Statistic: 1"
}
}
if($a -eq $null){
Write-Host "Message: Service is Healthy"
Write-Host "Statistic: 0"

The SolarWinds Powershell monitors are limited to 10 returned metric pairs (message and statistic), if there are more than 10 alerts returned, it will break. AS you are returning 5 messages, which appear to be identical in foreach($a in $alerts) loop, they won't have unique names, also probably causing you problems.
Are you running the script in Local Host or Remote Host execution mode? IF you are running it on a host without the Office365 commandlets, it'll fail.
Have you enabled debug logging, within the template? It's under Advanced at the top of the template editing view. Logs can be found in ProgramData\SolarWinds\Logs\APM, take note of your templateID or its componentIDs, as the logs will be referenced by them.

Related

Running commands as logged on user (remotely)

Thought I would share this quick function I made for myself, feel free to adapt it and improve it according to your needs.
Sometimes you want to run commands as the logged on user of a remote computer.
As you know, some commands show output for the user who runs it and if you run the same command with Invoke-Command, it won't return the user's information, but yours). Get-Printer is an example amongst many others.
There is no easy, quick way of running commands as the logged on user natively without any third-party apps like PsExec or others so I made this quick function that uses VBS, PS1 and Scheduled Task to make it happen.
It runs completly silently for the user (thanks to the VBS) and the output is shown in your console. Please note it assumes the remote computer has a C:\TEMP.
Created in a Windows 10, powershell v 5.1.17763.503 environement.
I don't pretend it's final and perfect, it's the simplest way I found to do what is needed and I just wanted to share it with you guys as it can be very useful!
Check the comments for explanation of the code and feel free to use it as you wish. Please share your version as I'm curious to see people improve it. A good idea would be to make it support multiple computers, but as I said it's a quick function I did I don't have too much time to put into refining it.
That being said, I had no problems using it multiple times as is :)
*Output returned is in form of a string, if you want to have a proper object, add '| ConvertFrom-String' and play with it :)
PLEASE NOTE: The surefire way of grabbing the username of who is currently logged on is via QWINSTA (since Win32_ComputerSystem - Username is only reliable if a user is logged on LOCALLY, it won't be right if a user is using RDP/RemoteDesktop). So this is what I used to grab the username, however, please note that in our french environement the name of the username property in QWINSTA is "UTILISATEUR",so you have to change that to your needs (english or other language) for it to work. If I remember correctly, it's "USERNAME" in english.
On this line:
$LoggedOnUser = (qwinsta /SERVER:$ComputerName) -replace '\s{2,22}', ',' | ConvertFrom-Csv | Where-Object {$_ -like "*Acti*"} | Select-Object -ExpandProperty UTILISATEUR
See code in the answer below.
function RunAsUser {
Param ($ComputerName,$Scriptblock)
#Check that computer is reachable
Write-host "Checking that $ComputerName is online..."
if (!(Test-Connection $ComputerName -Count 1 -Quiet)) {
Write-Host "$ComputerName is offline" -ForegroundColor Red
break
}
#Check that PsRemoting works (test Invoke-Command and if it doesn't work, do 'Enable-PsRemoting' via WMI method).
#*You might have the adjust this one to suit your environement.
#Where I work, WMI is always working, so when PsRemoting isn't, I enable it via WMI first.
Write-host "Checking that PsRemoting is enabled on $ComputerName"
if (!(invoke-command $ComputerName { "test" } -ErrorAction SilentlyContinue)) {
Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create -ArgumentList "powershell.exe -command Enable-PSRemoting -SkipNetworkProfileCheck -Force" | Out-Null
do {
Start-Sleep -Milliseconds 200
} until (invoke-command $ComputerName { "test" } -ErrorAction SilentlyContinue)
}
#Check that a user is logged on the computer
Write-host "Checking that a user is logged on to $ComputerName..."
$LoggedOnUser = (qwinsta /SERVER:$ComputerName) -replace '\s{2,22}', ',' | ConvertFrom-Csv | Where-Object {$_ -like "*Acti*"} | Select-Object -ExpandProperty UTILISATEUR
if (!($LoggedOnUser) ) {
Write-Host "No user is logged on to $ComputerName" -ForegroundColor Red
break
}
#Creates a VBS file that will run the scriptblock completly silently (prevents the user from seeing a flashing powershell window)
#"
Dim wshell, PowerShellResult
set wshell = CreateObject("WScript.Shell")
Const WindowStyle = 0
Const WaitOnReturn = True
For Each strArg In WScript.Arguments
arg = arg & " " & strArg
Next 'strArg
PowerShellResult = wshell.run ("PowerShell " & arg & "; exit $LASTEXITCODE", WindowStyle, WaitOnReturn)
WScript.Quit(PowerShellResult)
"# | out-file "\\$ComputerName\C$\TEMP\RAU.vbs" -Encoding ascii -force
#Creates a script file from the specified '-Scriptblock' parameter which will be ran as the logged on user by the scheduled task created below.
#Adds 'Start-Transcript and Stop-Transcript' for logging the output.
$Scriptblock = "Start-Transcript C:\TEMP\RAU.log -force" + $Scriptblock + "Stop-Transcript"
$Scriptblock | out-file "\\$ComputerName\C$\TEMP\RAU.ps1" -Encoding utf8 -force
#On the remote computer, create a scheduled task that runs the .ps1 script silently in the user's context (with the help of the vbs)
Write-host "Running task on $ComputerName..."
Invoke-Command -ComputerName $ComputerName -ArgumentList $LoggedOnUser -ScriptBlock {
param($loggedOnUser)
$SchTaskParameters = #{
TaskName = "RAU"
Description = "-"
Action = (New-ScheduledTaskAction -Execute "wscript.exe" -Argument "C:\temp\RAU.vbs C:\temp\RAU.ps1")
Settings = (New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -DontStopOnIdleEnd)
RunLevel = "Highest"
User = $LoggedOnUser
Force = $true
}
#Register and Start the task
Register-ScheduledTask #SchTaskParameters | Out-Null
Start-ScheduledTask -TaskName "RAU"
#Wait until the task finishes before continuing
do {
Write-host "Waiting for task to finish..."
$ScheduledTaskState = Get-ScheduledTask -TaskName "RAU" | Select-Object -ExpandProperty state
start-sleep 1
} until ( $ScheduledTaskState -eq "Ready" )
#Delete the task
Unregister-ScheduledTask -TaskName "RAU" -Confirm:$false
}
Write-host "Task completed on $ComputerName"
#Grab the output of the script from the transcript and remove the header (first 19) and footer (last 5)
$RawOutput = Get-Content "\\$ComputerName\C$\temp\RAU.log" | Select-Object -Skip 19
$FinalOutput = $RawOutput[0..($RawOutput.length-5)]
#Shows output
return $FinalOutput
#Delete the output file and script files
Remove-Item "\\$ComputerName\C$\temp\RAU.log" -force
Remove-Item "\\$ComputerName\C$\temp\RAU.vbs" -force
Remove-Item "\\$ComputerName\C$\temp\RAU.ps1" -force
}
#____________________________________________________
#Example command
#Note: Sometimes Start-Transcript doesn't show the output for a certain command, so if you run into empty output, add: ' | out-host' or '| out-default' at the end of the command not showing output.
$Results = RunAsUser -ComputerName COMP123 -Scriptblock {
get-printer | Select-Object name,drivername,portname | Out-host
}
$Results
#If needed, you can turn the output (which is a string for the moment) to a proper powershell object with ' | ConvertFrom-String'

Create local user as part of Administrator group on Windows 10

Setup:
We are all in domain environment. Active Directory is Windows Server 2012 R2
Client Workstations are mix of Windows 10 versions (1703 and 1709)
Need to create user "Servis" on all workstation and place it to local Administrator group. I will input a text file with the host names.
This is the script im trying to make it work, but no success.
The user is created, but user is not added to local admin group.
This is the error i get :
Error creating Service23 on WinNT://WS-TEST: The following exception occurred while retrieving member "add": "The network path was not found.
$computers = Get-Content -path C:\Scripts\CreateLocalUser\New\Computers.txt
$username = "Servis"
$password = "P4$$w0rd!##"
Foreach ($computer in $computers) {
$users = $null
$computer = [ADSI]"WinNT://$computername"
Try {
$users = $computer.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username already exists" -ForegroundColor Green
}
Else {
$user_obj = $computer.Create("user", "$username")
$user_obj.SetPassword($password)
$user_obj.SetInfo()
$user_obj.Put("description", "$username")
$user_obj.SetInfo()
$user_obj.psbase.invokeset("AccountDisabled", "False")
$user_obj.SetInfo()
$users = $computer.psbase.children | select -expand name
if ($users -like $username) {
Write-Host "$username has been created on $($computer.name)"
$group = [ADSI]("WinNT://" + $computername + "/administrators,group")
$group.add("WinNT://" + $computername + "/" + $username + ",user")
}
Else {
Write-Host "$username has not been created on $($computer.name)"
}
}
}
Catch {
Write-Host "Error creating $username on $($computer.path): $($Error[0].Exception.Message)"
}
}
Once you've defined your credential correctly with a password in a SecureString format creating a local admin is a 2 step process:
Create a user
Add that user to the Local Administrators group
These few lines are the powershell code needed:
$username = "Servis"
$password = ConvertTo-SecureString -AsPlainText "P4$$w0rd!##" -Force
New-LocalUser "$username" -Password $password -FullName "$username" -Description "Local admin $username"
Add-LocalGroupMember -Group "Administrators" -Member "$username"
If you want make you script more robust you should consider to create some Pester tests and add these checks to your script:
Validate if your file exists
Validate the content of the file (if is an IP or a FQDN with a regex)
Test if the host is reachable (e.g. Test-Connection -computername $computer -count 1 -quiet) before connecting
Using invoke-command with computername and argumentlist (username, password)
Check if the user was created successfully and is a member of the administrator group if not throwing an error
Write a log file to keep trace of all the tasks completed (by who, when on what host and so on).
I wrote a blog post on www.scriptinglibrary.com on few better ways of completing this task if you're interested.

PowerShell script fails to authenticate user when running Invoke-Command

I've recently created a little script that allows me to get the disk size and free space of 2 servers at each school site when I provide the script with the schools 4 digit site code.
First it pulls the information on the sites from a .csv file, and then uses that information to put together a string for the DC FQDN hostname, and the .10 server.
Then it requests the password for my elevated access account used to get the information on the disks.
I am having an issue where when the script creates the script block and then uses Invoke-Command and sends the script block to the servers, and provides back the PowerShell object with the information.
The error provided is as per below:
[{ServerName}] Connecting to remote server {ServerName} failed with the
following error message : WinRM cannot process the request. The following
error with errorcode 0x80090311 occurred while using Kerberos authentication:
There are currently no logon servers available to service the logon request.
Possible causes are:
-The user name or password specified are invalid.
-Kerberos is used when no authentication method and no user name are specified.
-Kerberos accepts domain user names, but not local user names.
-The Service Principal Name (SPN) for the remote computer name and port does
not exist.
-The client and remote computers are in different domains and there is no trust
between the two domains.
After checking for the above issues, try the following:
-Check the Event Viewer for events related to authentication.
-Change the authentication method; add the destination computer to the WinRM
TrustedHosts configuration setting or use HTTPS transport.
Note that computers in the TrustedHosts list might not be authenticated.
-For more information about WinRM configuration, run the following command:
winrm help config. For more information, see the about_Remote_Troubleshooting
Help topic.
+ CategoryInfo : OpenError: ({ServerName}:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : AuthenticationFailed,PSSessionStateBroken
Things I've tried:
Resetting my password
Altering the Authentication type to Basic
Getting others to try the same thing - some have the same issue, others do not
Other users on my workstations also have the same issue
I re-imaged my workstation and it worked for a bit, but then stopped again as it appeared to stop after the device installed software updates, so I'm in the middle of uninstalling those updates, however two of them won't allow me to uninstall, I assume they're forced installs by Microsoft and required to be installed (The uninstall button disappears when selected) - KB4019472 and KB4049065.
Device is running Windows 10 1607 v14393.1944, PowerShell v5.1.
There is a one-way trust between the domain I am in and the domains the DC1 and MS10 (.10) are in, the domains trust us, but we don't trust the domains.
The account I use is local admin on the device via a nested AD Group, across all domains.
I'm not very understanding of Kerberos, so any help would be amazing.
The script is below:
Note: I've had to remove some parts, so I've filled the area with what would be there (i.e. {String} where there would just be standard text, and {FQDNServerName} where there would be a FQDN server name written as text, or {Region} where I would have had the region written as text}).
$csvSchoolsLoc = "{FQDNServerName}\SharedReports$\SchoolsExport.csv"
$Schools = Import-Csv $csvSchoolsLoc -Delimiter "`t" -Header LocCode,SchoolName,SchoolAddress,SchoolPhoneNumber,SchoolFaxNumber,SchoolOfficerInCharge,DistrictCode,DistrictNumeric,RegionCode,RegionNumeric,LSD,WANLinkType,RouterName,RouterIP,RouterStatus,OneSchemaGraphUrl,OneSchemaSiteUrl,SCCMSiteID,SiteAdminNetwork,ProxyServerIP,PrimaryDcName,PrimaryDcIP,PrimaryDcOS,PrimaryDcVersion,PrimaryDcPatch,Style
#Gets the users credentials for their GBN ZZ account - this is used throughout the script for authentication
$username = "{Region}\zz-$env:USERNAME"
$mycreds = Get-Credential -UserName $username -Message "Enter your password for {region}\zz-$env:USERNAME"
Clear-Host
Write-Host "What is the schools 4 digit site code?" -ForegroundColor Magenta
$Global:SiteCode = Read-Host
Function Main {
Clear-Host
$SchoolName = $schools | Where-Object {$_.LocCode -eq $SiteCode} | ForEach-Object SchoolName
$Region = $schools | Where-Object {$_.LocCode -eq $SiteCode} | ForEach-Object RegionCode
Write-Host "Getting details for: " -ForegroundColor Gray -NoNewline; Write-Host "$SchoolName - $SiteCode - ($Region)"-ForegroundColor Yellow
$DC1 = "{String}$($Region)$($SiteCode)001.$region.{String}.{String}.{String}"
$MS10 = "{String}$($Region)$($SiteCode)010.$region.{String}.{String}.{String}"
if (Test-Connection -ComputerName $DC1 -Count 2 -Delay 1 -Quiet) {
$DC1Run = $true
} else {
$DC1Run = $false
}
if (Test-Connection -ComputerName $MS10 -Count 2 -Delay 1 -Quiet) {
$MS10Run = $true
} else {
$MS10Run = $false
}
$ScriptBlock = {
$DiskCTotal = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='C:'" -Impersonation 3 | ForEach-Object {$_.size / 1GB}
$DiskCFree = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='C:'" -Impersonation 3 | ForEach-Object {$_.freespace / 1GB}
$DiskZTotal = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='Z:'" -Impersonation 3 | ForEach-Object {$_.size / 1GB}
$DiskZFree = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='Z:'" -Impersonation 3 | ForEach-Object {$_.freespace / 1GB}
return #{
'ZFreeSpace' = $DiskZFree
'CFreeSpace' = $DiskCFree
'ZTotalSize' = $DiskZTotal
'CTotalSize' = $DiskCTotal
}
}
if (($DC1Run -eq $true) -and ($MS10Run -eq $true)) {
$ServerDC1 = Invoke-Command -ComputerName $DC1 -Credential $mycreds -ScriptBlock $ScriptBlock
$ServerMS10 = Invoke-Command -ComputerName $MS10 -Credential $mycreds -ScriptBlock $ScriptBlock
#Clear-Host
Write-Host -ForegroundColor Yellow "$SchoolName - $SiteCode - ($Region)"
Write-Host -ForegroundColor Cyan "Server $DC1 - Domain Controller"
Write-Host "$([math]::round($ServerDC1.CFreeSpace,2)) GB free on C Drive (Total Size $([math]::round($ServerDC1.CTotalSize,2)) GB)"
Write-Host "$([math]::round($ServerDC1.ZFreeSpace,2)) GB free on Z Drive (Total Size $([math]::round($ServerDC1.ZTotalSize,2)) GB)"
Write-Host ""
Write-Host -ForegroundColor Cyan "Server $MS10 - Distribution Point"
Write-Host "$([math]::round($ServerMS10.CFreeSpace,2)) GB free on C Drive (Total Size $([math]::round($ServerMS10.CTotalSize,2)) GB)"
Write-Host "$([math]::round($ServerMS10.ZFreeSpace,2)) GB free on Z Drive (Total Size $([math]::round($ServerMS10.ZTotalSize,2)) GB)"
} else {
#Clear-Host
Write-Host -ForegroundColor Yellow "$SchoolName - $SiteCode - ($Region)"
Write-Host -ForegroundColor Cyan "Server $DC1 - Domain Controller"
if ($DC1Run) {
Write-Host "DC1 connection status is running" -ForegroundColor Green
} else {
Write-Host "DC1 connection status is down" -ForegroundColor Red
}
Write-Host ""
Write-Host -ForegroundColor Cyan "Server $MS10 - Distribution Point"
if ($MS10Run) {
Write-Host "MS10 connection status is running" -ForegroundColor Green
} else {
Write-Host "MS10 connection status is down" -ForegroundColor Red
if ($DC1Run -eq $true) {
$RDP = Read-Host -Prompt "Would you like to RDP to $DC1 'Y'"
if ($RDP -eq "Y") {
Start-Process -FilePath "$env:windir\System32\mstsc.exe" -ArgumentList "/v:$DC1" -Wait -WindowStyle Maximized
}
}
}
}
Write-Host ""
Write-Host "What is the next schools 4 digit site code? -or- Press Enter to retry the above site again" -ForegroundColor Magenta
$Entry = Read-Host
if ($Entry -eq "") {
# Do nothing
} else {
$Global:SiteCode = $Entry
}
}
$x = 0
do {
Main
} until ($x -gt 0)
EDIT: The uninstall of the software updates did not fix the issue, so unless it's something to do with those 2 updates that I can't uninstall it doesn't appear to be Software Updates.
It turns out that the domains I am trying to reach were not in my TrustedHosts config for WinRM.
By using the following command, I was able to add the domains (of which I have numerous) to the TrustedHosts using the '*' wildcard.
NOTE: I have replaced part of the domain with {String} where it would normally have part of the domain name for confidentiality reasons.
winrm set winrm/config/client #{TrustedHosts="<local>,*.{string}.edu.au"}

Powershell script to restart service

I got this script from a blog and modified it to suit my environment. However I am having problems iterating through the foreach loop and getting the service status or the remote computers ($unregisteredVM).
It seems as if the Get-Service was trying to query the computer executing the script instead of the remote computers.
Also I tried running the portion of the script which grabs the status of the computer and set that variable as the -Computername parameter and it doesn't seem to take it.
$icaservicestate = Get-Service PorticaService -ComputerName $unregisteredVM | select status
What am i missing? Below is the entire code.
##Load Citrix Modules
asnp Citrix.*
#Variables for email
[string[]]$recipients = "xxxxx#xxxxxx.com"
$fromEmail = "xxxxx#xxxx.com"
$server = "itopia-us.mail.protection.outlook.com"
$date= Get-Date
##Check for VMs on and unregistered
$unregisteredVMs = Get-BrokerDesktop -RegistrationState Unregistered | Select MachineName
[string]$emailVMs = Get-BrokerDesktop -RegistrationState Unregistered | Select MachineName | ft -wrap -autosize | Out-String
IF (!$unregisteredVMs) {
##Send all clear email
[string]$emailBody = "There were no powered on desktops in an unregistered state."
send-mailmessage -from $fromEmail -to $recipients -subject " XenDesktop Daily Check - $date" -body $emailBody -priority High -smtpServer $server
}
Else {
##If powered-on and unregistered, perform a forceful restart
foreach ($unregisteredVM in $unregisteredVMs)
{
$icaservicestate = Get-Service PorticaService -ComputerName $unregisteredVM | select status
IF ($icaservicestate = Stopped) {
Set-Service -Name PorticaService -Status Running
}
Else {
sc \\$unregisteredVM start PorticaService
}
#Write-Host "Hello, I am unregistered: $unregisteredVM"
}
#Send an email report of VMs to be restarted due to being in an unregistered state
[string]$emailBody = "The following desktops were forcefully restarted due to not registering with the DDCs in a timely manner. `n $emailVMs"
send-mailmessage -from $fromEmail -to $recipients -subject " XenDesktop Daily Check - $date" -body $emailBody -priority High -smtpServer $server
}
I'm not sure if this is your entire problem but I don't think this is what you want:
IF ($icaservicestate = Stopped)
That assigns the result of executing a command named Stopped to the variable $icaservicestate. I doubt you have a command named Stopped. For equality comparison use -eq and quote Stopped:
IF ($icaservicestate -eq 'Stopped') { ... }
There are two potential reasons you may not be getting the result you want.
First: In Powershell a single equals sign is the assignment operator.
Your if statement line 24 is re-assigning the value of $icaservicestate to an error
$icaservicestate = Get-Service PorticaService -ComputerName $unregisteredVM | select status
IF ($icaservicestate = Stopped) {
Set-Service -Name PorticaService -Status Running
}
Use IF ($icaservice -eq 'stopped') {
Second: The line 23 Cmdlet Get-Service maybe failing due to line 11 the object you are passing to it
$unregisteredVMs = Get-BrokerDesktop -RegistrationState Unregistered | Select MachineName
In the above line you've generated an [array] of objects with each object having a single property called MachineName.
On line 23 you are trying to pass the objects to the ComputerName parameter of the Get-Service Cmdlet. To work around this you can use $unregisteredVM.MachineName in the Get-Service cmdlet
$icaservicestate = Get-Service PorticaService -ComputerName $unregisteredVM.MachineName | select status
You can read more about the way property values are passed in the pipeline by typing at the prompt:
help about_piplines and looking for 'ByValue' and 'ByPropertyName'
UPDATE:
if ($icaservicestate -eq 'Stopped') {
Get-Service -Name PorticaService -ComputerName $unregisteredVM.MachineName | Set-Service -Status Running
}
Previously, the line Set-Service -Name PorticaService -Status Running would be attempting to start the service on your local machine.
First we grab a reference to the PorticaService on the remote machine, then pipe that object to the Set-Service Cmdlet and set the status to running.
I think your script doesn't work because the machinename you get back from "get-brokerdesktop" is in the format domainname\vdiname. For "get-service -computername" you only need to enter the hostname.
To "isolate" the hostname I'd do:
$unregisteredVM=$unregisteredVM.machinename -replace ("domainname\," ")
$unregisteredVM=$unregsiteredVM.trim()
Now $unregisteredVM should contain only the hostname.

Use Alternate Credentials for PowerShell ADSI Provider WinNT Query

What am I trying to do?
Hi! I am writing a script that can accept 2 parameters, ComputerName and CheckWhatFile. The script will then access the computer (file server) specified by ComputerName and look for open file handles of CheckWhatFile.
The problem is the script needs to be executed by an administrative user. Our admins login as a non-privileged account. I want it to be as simple as clicking to run the script and only being prompted for the Get-Credentials box to enter there privileged account. I cannot use Invoke-Command unless you can find a way for it to not require having remote management turned on. The code below works when executed from a privileged PowerShell prompt that is started with runas /user: powershell.exe.
What I need help with
Help me find how to execute the 2 lines of code starting with netfile as a different user.
My code is:
param([string]$ComputerName = $null,[string]$CheckWhatFile = $null)
Import-Module ActiveDirectory
$Credentials = Get-Credential #Get Powerful Credentials
$netfile = [ADSI]"WinNT://$ComputerName/LanmanServer"
$netfile.Invoke("Resources") | foreach {
try
{
$Id = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
$ItemPath = $_.GetType().InvokeMember("Path", 'GetProperty', $null, $_, $null)
$UserName = $_.GetType().InvokeMember("User", 'GetProperty', $null, $_, $null)
$LockCount = $_.GetType().InvokeMember("LockCount", 'GetProperty', $null, $_, $null)
if($ItemPath -eq $CheckWhatFile)
{
$Culprit = Get-ADUser -Filter {SamAccountName -eq $UserName} -Credential $Credentials
Write-Host -ForegroundColor White -NoNewLine "Go Find "
Write-Host -ForegroundColor Yellow -NoNewLine $Culprit.Name
Write-Host -ForegroundColor White " and tell them to close the file!"
}
}
catch
{
}
}
Notes:
I have seen some examples with executing ADSI provider queries as a different user but they all relate to LDAP based queries not WinNT.
As it stands, the only way you're going to be able to do that is to have them RDP to the file server using the Admin credentials and run the script there. That's the only way they're going to get a powershell console to be able to see that output. Without powershell remoting enabled you can only get a local session, and that means either a local logon or RDP.
Something like this might work:
$provider = "WinNT://$ComputerName/LanmanServer"
$cred = Get-Credential
$netfile = New-Object DirectoryServices.DirectoryEntry(
$provider, $cred.UserName, $cred.GetNetworkCredential().Password
)
$netfile.Invoke("Resources") | % {
...
}