Powershell Get-Acl for folders without access permissions - powershell

I wrote a script, which gives me all the permissions of a folder + subfolders for a user/group. However, the script only works, if my user has at least read permissions on all these folders. If he has no permissions, get-acl is denied.
Is there any way to work around this, as I don't want to manually switch my user everytime I execute this script.
Can I execute a powershell script with a different user? And if yes, how?
Thank you in advance, Colin

You have a few options that I can think of:
Option 1:
Create a helper file with the actual code you want to run and call it script.ps1 for instance:
[array]$users = "user1","user2","user3"
foreach($user in $users){
$creds = Get-Credential -UserName $user -Message "Enter the Users Password"
$Session = New-PSSession -Credential $creds
Invoke-Command -Session $Session -FilePath C:\Path\to\some\script.ps1
}
Option 2: Run a job for each user. After every task is finished, the new user credentials will be asked. Just add the code to the scriptblock
[array]$users = "user1","user2","user3"
foreach($user in $users){
$creds = Get-Credential -UserName $user -Message "Enter the Users Password"
$target = $user
$job = Start-Job -scriptblock {
param ($username)
Get-Acl C:\Users\$user #Bla bla the rest of your script
} -Args $user -credential $creds
do{
#Wait for the job to finish
}until($job.State -ne "Running")
Write-Host "Job finished with state $($job.State)"
}
Hope this helps!
Note that the creds object can also be automated, if you don't wish to type all the time. (Security principles not taken into account ;) )
$users = #()
$users += #{
username = "User1"
password = "Pass123!"
}
$users += #{
username = "User2"
password = "Pass123!"
}
foreach($user in $users){
$creds = New-Object System.Management.Automation.PSCredential($user.username,($user.password | ConvertTo-SecureString -AsPlainText -Force))
#Add the rest of the script from the chosen option
}

Related

how can i add credentials in New-PSSession? everytime i face the login-prompt (powershell)

im trying to schedule a powershellscript which changes the calender permissions of users within the group "kalender_rechten" to limited details. however im facing the login prompt on new-pssesion. how can i add the $credObject into New-PSSession, without the loginprompt?
#Start transcript
Start-Transcript -Path C:\temp\Set-DefCalPermissions.log -Append
#get credentials to authenticate
$username = "test.onmicrosoft.com"
$pwdTxt = Get-Content "C:\test\test\pw.txt"
$securePwd = $pwdTxt | ConvertTo-SecureString
$credObject = New-Object System.Management.Automation.PSCredential -ArgumentList
$username, $securePwd
#authenticate admin office365
get-credential $credObject
#create session Office365
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri
https://outlook.office365.com/powershell-liveid/ -Credential $credObject -Authentication
Basic –AllowRedirection
$credObject
#import Office365/exchange commands to PowerShell console
Import-PSSession $Session
# Get all user mailboxes
$Users = Get-DistributionGroupMember -Identity "Kalender_rechten"
# Permissions
$Permission = "LimitedDetails"
# Calendar name languages
$FolderCalendars = #("Agenda", "Calendar", "Calendrier", "Kalender")
# Loop through each user
foreach ($User in $Users) {
# Get calendar in every user mailbox
$Calendars = (Get-MailboxFolderStatistics $User.Identity -FolderScope Calendar)
# Loop through each user calendar
foreach ($Calendar in $Calendars) {
$CalendarName = $Kalender_rechten
# Check if calendar exist
if ($FolderCalendars -Contains $CalendarName) {
$Cal = $User.Identity.ToString() + ":\$CalendarName"
$CurrentMailFolderPermission = Get-MailboxFolderPermission -Identity $Cal - User Default
# Set calendar permission / Remove -WhatIf parameter after testing
Set-MailboxFolderPermission -Identity $Cal -User Default -AccessRights
$Permission -WarningAction:SilentlyContinue -WhatIf
# Write output
if ($CurrentMailFolderPermission.AccessRights -eq "$Permission") {
Write-Host $User.Identity already has the permission
$CurrentMailFolderPermission.AccessRights -ForegroundColor Yellow
}
else {
Write-Host $User.Identity added permissions $Permission -ForegroundColor Green
}
}
}
}
Stop-Transcript

How to provide unique credentials for Set-Content calls

I have a powershell script that simply updates a file on a couple different webservers. Each of these web servers have different local credentials that I need to provide in order to access the file in question. How can I update my script to allow for this?
#message
$statusMessage = "hello world"
#servers to update
$servers = #("1.1.1.1","2.2.2.2")
#update files
foreach ($server in $servers) {
Set-Content -Path "\\$server\c$\blah\foo.htm" -Value $statusMessage
}
Again, each server has it's own local Admin credentials that I need to use.
One way to do this, if you really are forced to use local accounts (avoiding this problem is one of the purposes of having a domain), is to authenticate on the server using net use, copy the file, then disconnect. Example:
$userName = Read-Host "Enter user name for computer1"
net use \\computer1\ipc$ /user:$userName *
Set-Content \\computer1\c$\whatever\file.htm "Content here"
net use \\computer1\ipc$ /delete
Of course you can generalize the computer name within the loop. In this example, you will have to manually enter the user name and password for each computer.
Since the -Credential parameter of Set-Content doesn't seem to actually work (as Bill_Stewart pointed out) you basically have 3 options AFAICS:
Use net use to authenticate a session as Bill suggested in his answer, then write to the UNC path.
Map a network drive, either via net use or the PoSh way:
$username = 'Administrator'
$password = ConvertTo-SecureString 'password' -AsPlainText -Force
$cred = New-Object Management.Automation.PSCredential ($username, $password)
$drive = New-PSDrive -Name X -PSProvider FileSystem -Root "\\$server\c$\blah" -Persist -Credential $cred
Set-Content -Path 'X:\foo.htm' -Value $statusMessage
$drive | Remove-PSDrive
Run Set-Content on the remote server and have it write to a local path.
$username = 'Administrator'
$password = ConvertTo-SecureString 'password' -AsPlainText -Force
$cred = New-Object Management.Automation.PSCredential ($username, $password)
Invoke-Command -Computer $server -ScriptBlock {
Param($msg)
Set-Content -Path C:\blah\foo.html -Value $msg
} -ArgumentList $statusMessage -Credential $cred
For both PowerShell approaches you'll have to prepare a PSCredential object as shown above, or just pass the username (in which case you'll be prompted for the password).

PowerShell script module doesn't return any info

I have the following module:
Function Get-ProcessHash {
param($ComputerName)
$username = $ComputerName + '\localadm'
$password = ConvertTo-SecureString 'supersecret' -AsPlainText -Force
$cred = New-Object -typename System.Management.Automation.PSCredential -ArgumentList $username, $password
Invoke-Command -ComputerName $ComputerName -Credential $cred -Authentication Negotiate -ScriptBlock {
Get-Process * | Select-Object Id, Name, ProductVersion, Company, Path, #{l="SHA256";e={if ($_.Path -ne $null) { (Get-FileHash $_.Path).Hash}}}
}
}
This script module is located at C:\Users\<username>\Documents\WindowsPowerShell\Modules\SuperModule\SuperModule.psm1. I can see its functions via Get-Command -Module SuperModule. If I run the content of the script manually, outside of the function, it will work and return all the values, but when I try to run the function as PS C:\Users\<username>\Documents\Scripts> Get-ProcessHash US0001 it doesn't return a thing.
The credentials are valid, I can execute the script outside of the module and it works.
As Matt said in the comments, the solution was simple:
"Have you been making changes to this module while it was loaded? If you close all active PowerShell sessions and try again is your issue the same?"

Create Local User with Custom User Folder in Powershell

I am trying to create a new Win 2008 server local user and assign the user a different profile path. I don't want Windows to generate all the files under C:\Users\newUser, instead, I'd like to have it do that in D:\customDir\newUser. Does anyone know of a way to do this?
So far this is what I have:
$users= #("U1","U2","U3")
$computer = [ADSI]"WinNT://$env:COMPUTERNAME,computer"
$group = [ADSI]"WinNT://$env:COMPUTERNAME/MyCustomGroup,group"
$users | foreach {
$userName = $_
$userPath = "D:\customDir\$userName"
echo "Creating $userName..."
$user = $computer.Create("User",$userName)
$user.put("description","User $userName Description")
#$user.put("profilePath",$userPath) #This does not work, throws an error
#$user.put("homeDirDrive","D:") #This appears to be ignored when uncommented
$user.setpassword($userName)
$user.setInfo()
$group.add($user.Path)
#run cmd from user account to create profile files/folders
$spw = ConvertTo-SecureString $userName -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $userName,$spw
Start-Process cmd /c -WindowStyle Hidden -Credential $cred -ErrorAction SilentlyContinue
}
The script successfully creates the users and adds them to the custom group, but all the files/folders end up in C:\Users\U*
To the OP,
Thanks for this piece, I was trying to figure out how to make this work for me:
run cmd from user account to create profile files/folders
$spw = ConvertTo-SecureString $userName -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $userName,$spw
Start-Process cmd /c -WindowStyle Hidden -Credential $cred -ErrorAction SilentlyContinue
but I had to modify the last line to get it to work:
Start-Process cmd /c -Credential $cred -ErrorAction SilentlyContinue -LoadUserProfile
This works fine.
$loginName="ChrisMcCormack"
$newPass="123456ABCDEFG" # obviously generate a proper password...
$desc="average user"
$localHost=[ADSI]"WinNT://localhost"
$newUser=$localHost.Create("user",$loginName);
$newUser.setPassword($newPass);
$newUser.put("HomeDirectory","c:\users\$loginName");
$newUser.put("description",$desc);
$newUser.setInfo();
You can also use:
$spw = ConvertTo-SecureString $newPass -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $loginName,$spw
Start-Process cmd /c -WindowStyle Hidden -Credential $cred -ErrorAction SilentlyContinue
to create the users directories without logging the user on.
Chris
Here is the way I use according to the underlaying COM component object model and the IADsUser interface.
$obj = [ADSI]"WinNT://$env:COMPUTERNAME"
$user1=$obj.create("user", "utilisateur1")
$user1.PasswordExpired=0
$user1.Invoke("setpassword","test.2012")
$user1.Invoke("put", "HomeDirectory", "c:\silogix")
$user1.Invoke("put", "Profile", "c:\docs")
$user1.Invoke("put", "LoginScript", "test.cmd")
$user1.CommitChanges()
Here is the result.
The only thing I can think of for you would be to change it at the registry level. Note that I'm not recommending you mess with the registry, but this does do what you want -
The default directory for a new profile is determined by the ProfilesDirectory in HKLM:\Software\Microsoft\Windows NT\CurrentVersion\ProfileList, and by default is %SystemDrive%\Users, changing it to $userpath should do what you want -
$regpath = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\ProfileList"
$regname = "ProfilesDirectory"
set-itemproperty -path $regpath -name $regname -value $userpath
Hope that helps!

Adding Current User To Administrators Group

I'm working on a script that will check if a user is an Administrator and then if they're not it'll add them on the spot, logoff, and then I can log back on to test. This is the part I'm running into problems:
$Cred = Get-Credential ("$env:COMPUTERNAME\Administrator")
$Group = [ADSI]("WinNT://"+$env:COMPUTERNAME+"/Administrators,Group")
$User = $env:USERNAME
$Domain = $env:USERDOMAIN
Invoke-Command -Computername localhost -Cred $Cred -ScriptBlock {$Group.add("WinNT://$Domain/$User,user")}
Everytime I run this I get the following error:
You cannot call a method on a null-valued expression.
Any ideas what I can do to fix this issue?
Working solution:
$Cred = Get-Credential ("$env:COMPUTERNAME\Administrator")
$User = $env:USERNAME
$Domain = $env:USERDOMAIN
Invoke-Command -Computername localhost -Cred $Cred -ScriptBlock {
param ($User, $Domain, $ComputerName)
$Group = [ADSI]("WinNT://$ComputerName/Administrators,Group")
$Group.add("WinNT://$Domain/$User,user")
} -ArgumentList $User, $Domain, $ENV:COMPUTERNAME
Invoke-Command will know nothing about $Group variable, that's reason why it does not work like that. You need to pass your variables to scriptblock using -ArgumentList parameter.
Also: I would rather define things like $Group inside this scriptblock:
$Cred = Get-Credential ("$env:COMPUTERNAME\Administrator")
$User = $env:USERNAME
$Domain = $env:USERDOMAIN
Invoke-Command -Computername localhost -Cred $Cred -ScriptBlock {
param ($User, $Domain, $ComputerName)
$Group = [ADSI]("WinNT://$ComputerName/Administrators,Group")
$Group.add("WinNT://$Domain/$User,user")
} -ArgumentList $User, $Domain, $ENV:COMPUTERNAME
HTH
Bartek
PS: just one question: why not doing it simple way, with:
net localgroup administrators domain\user /add