Thursday, 16 April 2015

PowerShell - Testing if a String is NULL or EMPTY

Checking if a string is NULL or EMPTY is very common requirement in Powershell script. If we do not checked that we will get some unwanted results when we try to perform some operation on that string variable which is empty or null.

The following method is used to check if a string is NULL or empty.
$mystring ='hello'
if($mystring) {            
    Write-Host "Your string is not EMPTY"            
} else {            
    Write-Host "Your string is EMPTY or NULL"            
}
We can also use the .NET Class “System.String” to check null or empty string. It has a method IsNullOrEmpty() which returns true if the passed string is null or empty. Check the below example.
$mystring ='hello'
IF([string]::IsNullOrEmpty($mystring)) {            
    Write-Host "Your string is EMPTY or NULL"            
} else {            
    Write-Host "Your string is not EMPTY"            
}
We can also use the method IsNullOrWhiteSpace() from “System.String” class to detect a given string is NULL or EMPTY and whether it has WHITESPACE.
$mystring = " "            
IF([string]::IsNullOrWhiteSpace($mystring)) {            
    Write-Host "Your string is NULL or EMPTY or it has WHITESPACE"            
} else {            
    Write-Host "Your string is not EMPTY"            
}     
Note: The method IsNullOrWhiteSpace() is available only from .NET Frmaework 4.0, so, this method do not work in Powershell 2.0 and it will work only from Powershell 3.0.

You will get below error, when you run this method in Powershell 2.0.

IsNullOrWhitespace : Method invocation failed because [System.String] doesn’t contain a method named ‘IsNullOrWhiteSpace’
Read More...

Friday, 10 April 2015

Powershell - Get AD Users Group Membership

In this article, I am going write PowerShell script to find and list Active Directory Groups of an AD user is a Member Of using the PowerShell's cmdlet Get-ADPrincipalGroupMembership.

Powershell command to list AD User Group Membership:

Get-ADPrincipalGroupMembership [-Identity]
The Identity parameter specifies the user, computer, or group object that you want to determine group membership for. You can identify a user object by its distinguished name (DN), GUID, SID or SAMAccountName.

List Group Names of an AD User is Member Of

The below powershell command find and list all Active Directory Groups which contains the user account Morgan as member.
Import-Module ActiveDirectory
Get-ADPrincipalGroupMembership Morgan |
 Select Name,DistinguishedName

Export set of AD Users Group Membership to CSV

The below PowerShell script get AD users from the OU TestOU and enumerate membership of all AD Users. It writes the group membership output into csv file using the powershell cmdlet Add-Content.
Import-Module ActiveDirectory
$CSV_File_Path = "C:\ADGroupMembership.csv"
$Header = "UserName,Groups"
 
If (Test-Path $CSV_File_Path){
 Remove-Item $CSV_File_Path
}
 
Add-Content -Value $Header -Path $CSV_File_Path 

$users = Get-ADUser -SearchBase "OU=TestOU,DC=TestDomain,DC=Com" -Filter * 

foreach($user in $users){
  $groupNames = ""
  $groups = Get-ADPrincipalGroupMembership $user.SamAccountName 
  foreach($group in $groups){
    if($groupNames -eq "")
     {
       $groupNames = $group.name
     }
    else
     {
       $groupNames = $groupNames +","+$group.name
     }
  }

  $info=$user.SamAccountName+','+'"'+$groupNames+'"'
 Add-Content -Value  $info -Path $CSV_File_Path 
}

CSV Output of AD Users Group Membership:

Find and Export AD Users Group Membership to CSV
Read More...

C# - Get PowerShell Output from MultiValuedProperty Value

In C#, you can execute powershell commands and get output in separate runspace. The following C# example returns the exchange server's mailbox audit report. The audit setting fields (AuditDelegate,AuditAdmin,AuditOwner) are multi-valued property field, so we can not read value directly from this field. The datatype of this field is "Deserialized.Microsoft.Exchange.Data.Directory.ADMultiValuedProperty`1[[Microsoft.Exchange.Data.Directory.MailboxAuditOperations, Microsoft.Exchange.Data.Directory, Version=14.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]". So, here, I have written the C# code to extract value from ADMultiValuedProperty field.
public static void GetMailBoxAuditReport()
{
    string shellUri = "http://schemas.microsoft.com/powershell/Microsoft.PowerShell";
    var secured = new SecureString();
    foreach (char letter in "MyPassword")
    {
        secured.AppendChar(letter);
    }
    secured.MakeReadOnly();
    var credential = new PSCredential(@"MyExchDomain\Administrator", secured);
    var connectionInfo = new WSManConnectionInfo(false, "MyExchServer", 5985, "/wsman", shellUri, credential);
    Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);
    runspace.Open();
    Pipeline pipeline = runspace.CreatePipeline();
    pipeline.Commands.AddScript("Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010");
    pipeline.Commands.AddScript("Get-Mailbox | Select Name, AuditEnabled, AuditLogAgeLimit,AuditAdmin,AuditDelegate,AuditOwner");
    Collection<PSObject> results = pipeline.Invoke();
    if (results.Count > 0)
    {
        foreach (PSObject psObject in results)
        {
            List<string> output = new List<string>();
            foreach (PSPropertyInfo psInfo in psObject.Properties)
            {
                if (psInfo.Value != null)
                {
                    string dataType = psInfo.TypeNameOfValue;
                    if (dataType.Contains("ADMultiValuedProperty"))
                    {
                        string multiValueOutput = string.Empty;
                        PSObject childObj = (PSObject)psInfo.Value;
                        foreach (PSObject info in (ArrayList)childObj.ImmediateBaseObject)
                        {
                            multiValueOutput += info.ToString() + ";";
                        }
                        output.Add(multiValueOutput);
                    }
                    else if (dataType.Equals("System.String[]"))
                    {
                        string[] childObj = (string[])psInfo.Value;
                        output.Add(string.Join(";", childObj));
                    }
                    else
                    {
                        output.Add(psInfo.Value.ToString());
                    }
                }
            }
            Console.WriteLine(string.Join(";", output.ToArray()));
            Console.WriteLine("----------------------");
        }
    }
}

Read More...

Wednesday, 8 April 2015

PowerShell - Convert Ticks to Date Time and Vise Versa

You can convert Date to Ticks and Ticks to Date Time using the PowerShell Get-Date cmdlet.

Convert Ticks to Date Time

Use the below powershell command to convert ticks to date.
Get-Date 635641048517131910

Wednesday, April 08, 2015 3:47:31 PM
You can also convert ticks to datetime by simple DateTime type casting.
[DateTime]635641048517131910

Wednesday, April 08, 2015 3:47:31 PM

Convert Date Time to Ticks

Use the below powershell command to convert date to ticks.
(Get-Date).ticks

635641051132584348
(Get-Date "04/20/2014").ticks

635335488000000000
Read More...

PowerShell - Convert Large Integer value to Date Time string

If you are working with Active Directory, you should have come across the attributes like LastLogonTimestamp. This LastLogonTimestamp attribute is stored in the Active Directory database as a Large Integer (TimeStamp) value so we need to convert it to a normal date format string to make it readable.

Use the following PowerShell command to Convert Large Integer value to Date Time string

$lastLogonTimestamp = "130724281432636780"
[DateTime]::FromFiletime([Int64]::Parse($lastLogonTimestamp))
PowerShell - Convert Large Integer value to Date Time string
Read More...

Event 1530 - Windows detected your registry file is still in use

Problem:

One of my installed Apllication's Windows Service not started automatically and I tried to start it manually, but it again failed to start, then I have started to analyze through event logs and find the below warning event 1530 with error message "Windows detected your registry file is still in use by other applications or services. The file will be unloaded now. The applications or services that hold your registry file may not function properly afterwards".
Log Name:      Application
Source:        Microsoft-Windows-User Profiles Service
Date:          4/8/2015 01:45:18 AM
Event ID:      1530
Level:         Warning
Computer:      myPC.myDomain.Com
Description:
Windows detected your registry file is still in use by other applications or services. The file will be unloaded now. The applications or services that hold 
your registry file may not function properly afterwards.  

 DETAIL - 
 1 user registry handles leaked from \Registry\User\S-1-5-21-745457877-148782331-813991262-2636_Classes:
Process 1984 (\Device\HarddiskVolume3\Program Files
\Program Files\MTS\MyService.exe) has opened key \REGISTRY\USER\S-1-5-21-745457877-148782331-813991262-2636_CLASSES

Cause:

After I have analyzed some time, found this warning event was logged due to service account (The service account used only to run widows service and it was not used to login into system). This warning event (1530) is logged by the behavior of system design.

Other related links

- http://support.microsoft.com/en-us/kb/947238
- http://answers.microsoft.com/en-us/windows/forum/windows_7-security/event-id1530-microsoft-windows-user-profiles/a1ca9fd0-5449-46b6-aae2-35e3edcf8425
- http://social.technet.microsoft.com/wiki/contents/articles/3134.user-profile-service-event-1530-the-windows-operating-system-detected-that-your-registry-file-is-still-in-use-by-other-applications-or-services.aspx
Read More...

Tuesday, 31 March 2015

Test Remote Powershell Management is Enabled or Not

We can check whether the powershell remoting is configured or not in a particular remote computer using the powershell cmdlet Test-WsMan. This command tests whether the WinRM service is running on the remote computer and the computers can communicate with each other.
Test-WsMan COMPUTER
The below command check whether powershell remoting is enabled or not in the remote computer MCOM12.
Test-WsMan MCOM12
The command displays powershell version if remote powershell management is successfully configured or otherwise it will displays an error message.

Check Powershell Remoting Management is Enabled or Not

Read More...

Sunday, 29 March 2015

Execute Remote PowerShell Commands

We can run powershell commands on remote computer using the powershell cmdlet Invoke-Command.

Syntax of Invoke-Command:
Invoke-Command -ComputerName COMPUTER -ScriptBlock { COMMAND } -credential USERNAME
COMPUTER - The name of the computer to connect.
COMMAND - The powershell command to run in remote computer
USERNAME - The user account to run the command as on the remote computer. You will be prompted to enter a password for the username.

The below sample execute the command on the remote computer MCOM12, find the remote host name and display as output.
Invoke-Command -ComputerName MCOM12 -ScriptBlock { 'This command running on {0}.' -f (hostname) } -credential Morgan

Remote PowerShell Session

If you want to run series of PowerShell commands on a remote computer, you can start a remote PowerShell session for the particular remote computer using the Enter-PSSession cmdlet and then you can run multiple commands, instead of running a single command:
Enter-PSSession -ComputerName COMPUTER -Credential USER
The below sample command creates new session for the remote computer MCOM12.
Enter-PSSession -ComputerName MCOM12 -Credential Administrator
Execute Remote PowerShell Commands
Read More...

Saturday, 28 March 2015

Enable PowerShell Remoting and Run Remote commands

You can configure Powershell Remoting on Computers running Windows 7 and later versions which includes WinRM 2.0 or later. The Windows PowerShell Remoting features are supported by the WS-Management protocol and the Windows Remote Management (WinRM) service that implements WS-Management in Windows.

Enabling PowerShell Remote Management includes following steps:

1. Start or restart the WinRM service.
2. Setting the WInRM service startup type to Automatic.
3. Creates a listener to accept requests from any Internet Protocol (IP) address.
4. Enabling Windows Firewall inbound rule exceptions for WS-Management traffic.

Follow the below steps to configure PowerShell Remoting:

1. Start Windows PowerShell with elevated privilege (Run as Administrator) by right-clicking the Windows PowerShell shortcut and selecting Run As Administrator.

2. Run the following command to enable Powershell Remoting.
Enable-PSRemoting -Force
This command starts the WinRM service, sets its startup type to Automatic, and creates a firewall rule that allows incoming connections. The -Force part of the command tells PowerShell to perform these actions without prompting you for each step.
If your computers are on a same domain network, running above command alone  activate Powershell Remoting. If your computers are not on a same domain network (i.e. if you are working from a home network or other domain network), you will need to perform a few more steps.

  - Run the Enable-PSRemoting -Force command also on the local computer where you want connect from.

  - On both computers (remote and local computers), configure the TrustedHosts setting so that both the computers will trust each other. Run the below command to allow any computer to connect remote powershell.
Set-Item wsman:\localhost\client\trustedhosts *
  Note: If you want to restrict computers (instead of any computers) that can connect, you could also replace the * with a comma-separated list of IP addresses or computer names.

 - Restart the WinRM service on both computers (remote and local computers) so that your new settings will take effect.
Restart-Service WinRM

Test Powershell Remote Connection

You can use the Test-WsMan cmdlet to test your remote configuration settings. This command tests whether the WinRM service is running on the remote computer and the computers can communicate with each other.
Test-WsMan MCOM12
Enable PowerShell Remoting and Run commands on Remote Computer

Run Remote Powershell Commands

Use the powershell cmdlet Invoke-Command to run a command on the remote system.

Syntax of remote powershell command:
Invoke-Command -ComputerName COMPUTER -ScriptBlock { COMMAND } -credential USERNAME
COMPUTER - The name of the computer to connect.
COMMAND - The powershell command to run in remote computer
USERNAME - The user account to run the command as on the remote computer. You will be prompted to enter a password for the username.

The below sample execute the command on the remote computer MCOM12, find the remote host name and display as output.
Invoke-Command -ComputerName MCOM12 -ScriptBlock { 'This command running on {0}.' -f (hostname) } -credential Morgan

Read More...

Tuesday, 24 March 2015

Powershell: Set AD User Must Change Password At Next Logon

We can set AD user property values using powershell cmdlet Set-ADUser. The Set-ADUser cmdlet modifies the properties of an Active Directory user. Normally, you can force an AD user to change password at next logon by setting the AD user's pwdLastSet attribute value as 0, but this Set-ADUser cmdlet supports the extended property ChangePasswordAtLogon, you can directly set True or False value in this property and the cmdlet itself internally update the pwdLastSet attribute.

Powershell command to reset user to change password at next logon:

Set-ADUser -Identity <samAccountName> -ChangePasswordAtLogon $true
The Identity parameter specifies the Active Directory user to modify. You can identify a user by its samAccountName, distinguished name (DN), GUID and SID.

Set Users Specific OU:

You can select AD users from specific OU and set user must change password at next logon by using Get-ADUser and Set-ADUser cmdlets. You can set target OU scope by using the parameter SearchBase in Get-ADUser cmdlet. This following command select and set pwdLastSet attribute value as 0 of the Active Directory users the Organization Unit 'TestOU'.
Import-Module ActiveDirectory
Get-ADUser -Filter * -SearchBase "OU=TestOU,DC=TestDomain,DC=Local" |
  Set-ADUser -ChangePasswordAtLogon:$True

Update Specific set of AD Users with Filter:

You can filter sepecific set of AD users by using SQL like filter with Get-ADUser, users who are not familiar with LDAP filter can easily use this filter to get only specific set of AD users
Import-Module ActiveDirectory
Get-ADUser -Filter 'department -like "*Admin*"' |
  Set-ADUser -ChangePasswordAtLogon:$True
You can also use LDAP filter with Get-ADUser powershell cmdlet with more flexibility to filter Active Directory users.
Import-Module ActiveDirectory
Get-ADUser -LDAPFilter '(Department=*Admin*)' |
  Set-ADUser -ChangePasswordAtLogon:$True

Modify Bulk AD Users Password Never Expire flag from CSV:

You can read Active Directory from csv file using Powershell cmdlet Import-CSV. Consider the CSV file ADUsers.csv (Ex file: Download ADUsers.csv) which contains set of AD users with the attribute samAccountName.

Set Bulk AD Users to Change Password At Next Logon from CSV
Import-Module ActiveDirectory
Import-Csv "C:\Scripts\ADUsers.csv" | ForEach-Object {
 $samAccountName = $_."samAccountName"
Get-ADUser -Identity $samAccountName | 
 Set-ADUser -ChangePasswordAtLogon:$True
}

Modify specific AD Group Members:

You can set user must change password at next logon for the specific AD group members by getting group members using Get-ADGroupMember cmdlet. The following powershell script select all the members TestGroup group and set the users to change password at next logon.
Import-Module ActiveDirectory
Get-ADGroupMember -Identity "TestGroup" |
  Set-ADUser -ChangePasswordAtLogon:$True
Read More...

Friday, 20 March 2015

Powershell: Set AD Users Password Never Expires flag

We can set Active Directory user property values using Powershell cmdlet Set-ADUser. The Set-ADUser cmdlet modifies the properties of an Active Directory user. Normally, you can configure an AD user as password never expire user by setting the flag DONT_EXPIRE_PASSWORD (65536) in the AD user's userAccountControl attribute, but this Set-ADUser cmdlet supports the extended property PasswordNeverExpires, you can directly set value in this property and the cmdlet itself internally update the userAccountControl flag.

Powershell command to Configure Password Never Expires flag:

Set-ADUser -Identity <samAccountName> -PasswordNeverExpires $true
The Identity parameter specifies the Active Directory user to modify. You can identify a user by its samAccountName, distinguished name (DN), GUID and SID.

Modify AD Users from Specific OU:

You can select AD users from specific OU and set as password never expire users by using Get-ADUser and Set-ADUser cmdlets. You can set target OU scope by using the parameter SearchBase in Get-ADUser cmdlet. This following command select and set as password never expires flag of Active Directory users from the Organization Unit 'TestOU'.
Import-Module ActiveDirectory
Get-ADUser -Filter * -SearchBase "OU=TestOU,DC=TestDomain,DC=Local" |
  Set-ADUser -PasswordNeverExpires:$True

Update Specific set of AD Users with Filter:

You can filter sepecific set of AD users by using SQL like filter with Get-ADUser, users who are not familiar with LDAP filter can easily use this filter to get only specific set of AD users
Import-Module ActiveDirectory
Get-ADUser -Filter 'department -like "*Admin*"' |
  Set-ADUser -PasswordNeverExpires:$True
You can also use LDAP filter with Get-ADUser powershell cmdlet with more flexibility to filter Active Directory users.
Import-Module ActiveDirectory
Get-ADUser -LDAPFilter '(Department=*Admin*)' |
  Set-ADUser -PasswordNeverExpires:$True

Modify Bulk AD Users Password Never Expire flag from CSV:

You can read Active Directory from csv file using Powershell cmdlet Import-CSV. Consider the CSV file ADUsers.csv (Ex file: Download ADUsers.csv) which contains set of AD users with the attribute samAccountName.

Modify Bulk AD Users Password Never Expire flag from CSV file
Import-Module ActiveDirectory
Import-Csv "C:\Scripts\ADUsers.csv" | ForEach-Object {
 $samAccountName = $_."samAccountName"
Get-ADUser -Identity $samAccountName | 
 Set-ADUser -PasswordNeverExpires:$True
}

Modify specific AD Group Members:

You can set password never expires flag for only specific Active Directory group members by getting AD group members using Get-ADGroupMember cmdlet. The following powershell script select all the members "TestGroup"  group and set as password never expire users.
Import-Module ActiveDirectory
Get-ADGroupMember -Identity "TestGroup" |
  Set-ADUser -PasswordNeverExpires:$True
Read More...

The type or namespace name 'automation' does not exist in the namespace 'system.management'

I have added the reference Assembly System.Management.Automation in my C# application to run PowerShell scripts from C# project. but I am getting following error during compilation of the code.
Error 30 The type or namespace name 'Automation' does not exist in the namespace 'System.Management' (are you missing an assembly reference?)
This is my C# code:
using System.Management.Automation;
using System.Management.Automation.Runspaces;
//-----------------------------------
static void Main(string[] args)
{
    Runspace runspace = RunspaceFactory.CreateRunspace();
    runspace.Open();
    Pipeline pipeline = runspace.CreatePipeline();
    pipeline.Commands.AddScript("Get-Date");
    Collection<PSObject> results = pipeline.Invoke();
    runspace.Close();
    StringBuilder stringBuilder = new StringBuilder();
    foreach (PSObject obj in results)
    {
        Console.WriteLine(obj.ToString());
    }
}

Fix/Solution:

The issue was fixed after I have changed the reference of System.Management.Automation to c:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll.

I have added the reference Assembly System.Management.Automation from the location "C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0" and my C# projects targets .NET Framework 3.5. Initially I didn't find the the reference System.Management.Automation.dll when I search the Assemblies in Add Reference window, so that I have added the reference by manual browse option from the location "C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0".

Finally I found that the assembly file System.Management.Automation.dll (under the folder PowerShell 3.0) is supported only .NET Framework 4.0, so that have changed the reference Assembly to c:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll to fix this issue.
Read More...

Wednesday, 18 March 2015

Change the location of Windows Search Index

If you enabled the Windows Search and Index service in your windows system, the file named "Windows.edb" will be placed under the location "C:\ProgramData\Microsoft\Search\Data\Applications\Windows" and its size will be growing day by day. You have to change the location of the file if you are facing disk storage size overflow problem due to this file.

Change location of Windows Search Index

By default, Search Index file(Windows.edb) stored at C:\ProgramData\Microsoft\Search\Data folder, which is a hidden system folder. You can change the location of the Search Index under Indexing Options in the Control Panel. Follow the steps to change the location of Windows Search Index.

1.  Open Control Panel in its ‘Large Icons view’, and click on Indexing Options.

Change the location of Windows Search Index

2.  In new Window, click on Advanced button.

Change the location of Windows Search Index

3.  Under the Index location section, click Select new button.

Change the location of Windows Search Index

4.  Select the folder where you want to store the new search index file and click on OK.

Change the location of Windows Search Index

Note:This process will restart Windows Search Service and Indexing and save the Search Index file at new location.
Read More...

Tuesday, 17 March 2015

TF400324: Team Foundation services are not available from server...

Problem:

We faced the TFS connection failure problem while connecting TFS source project from Visual Studio 2013. We got the error message "TF400324: Team Foundation services are not available from server - The underlying connection was closed: An unexpected error occurred on a receive".

Complete error message:

TF400324: Team Foundation services are not available from server TFS-Server.
Technical information (for administrator):
 The underlying connection was closed: An unexpected error occurred on a receive.

Solution:

After I have analysed some time, found the following quick fix to resolve this error.
  1. Close Visual Studio Solution and related applications.
  2. Browse the TFS AppData Cache folder path: %LocalAppData%\Microsoft\Team Foundation\5.0\Cache
  3. Delete all the contents under the folder Cache (don't worry it will be automatically re-created when you open Visual Studio and connect TFS again),
For better fix, you can refer this solution: http://www.codeproject.com/Articles/613214/TF-Team-Foundation-services-are-not-availabl
Read More...

C# - Set Full Control Permission to a Directory

In C#, we can easily add full access control permission on a file or folder for an user account or everyone (Everybody) account using .NET classes Directory and DirectorySecurity.

The below C# code set the full control permission on the given directory for the given user account. It also applies the full control permissions to folder, subfolders and files.
public static void SetFullAccessPermission(string directoryPath,string username)
{
    DirectorySecurity dir_security = Directory.GetAccessControl(directoryPath);
            
    FileSystemAccessRule full_access_rule = new FileSystemAccessRule(username,
                     FileSystemRights.FullControl, InheritanceFlags.ContainerInherit |   
                     InheritanceFlags.ObjectInherit,PropagationFlags.None,
                     AccessControlType.Allow);

    dir_security.AddAccessRule(full_access_rule);

    Directory.SetAccessControl(directoryPath, dir_security);
}
In some cases, situation may require us to configure full control permission to every users (Everyone/Everybody account). In that case, get the everyone identity from the enum WellKnownSidType.WorldSid instead of giving the string "Everyone" because the string value "Everyone" differs other languages. The below C# code set full access control permission on the given directory for everyone account.
public static void SetFullAccessPermissionsForEveryone(string directoryPath)
{
    //Everyone Identity
    IdentityReference everyoneIdentity = new SecurityIdentifier(WellKnownSidType.WorldSid,
                                               null);

    DirectorySecurity dir_security = Directory.GetAccessControl(directoryPath);

    FileSystemAccessRule full_access_rule = new FileSystemAccessRule(everyoneIdentity,
                    FileSystemRights.FullControl, InheritanceFlags.ContainerInherit |   
                     InheritanceFlags.ObjectInherit,PropagationFlags.None,
                     AccessControlType.Allow);
    dir_security.AddAccessRule(full_access_rule);

    Directory.SetAccessControl(directoryPath, dir_security);
}
Read More...