You have heard all of the warnings about shrinking databases and they are all true. It will fragment your indexes and is in general, muck up your database and shouldn't be done on a production system.

But, I generally do so on a weekly basis when I restore a backup on my workstation due to space on my SSD drive. 
Mind you, I didn't write this script but found it years ago. On other databases [250 GB], I created an SSIS package that will transfer the tables that I need and then recreate the indexes for that oh so fresh index feel.

DECLARE @DBFileName SYSNAME

DECLARE @TargetFreeMB INT

DECLARE @ShrinkIncrementMB INT

SET @DBFileName = 'Set Name of Database file to shrink'

-- Set Desired file free space in MB after shrink

SET @TargetFreeMB = 500
-- Set Increment to shrink file by in MB
SET @ShrinkIncrementMB = 100

SELECT [FileSizeMB] = convert(NUMERIC(10, 2),
round(a.size / 128., 2)),

[UsedSpaceMB] = convert(NUMERIC(10, 2),

round(fileproperty(a.NAME, 'SpaceUsed') / 128., 2)),

[UnusedSpaceMB] = convert(NUMERIC(10, 2),

round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2)),

[DBFileName] = a.NAME

FROM sysfiles a

DECLARE @sql VARCHAR(8000)
DECLARE @SizeMB INT
DECLARE @UsedMB INT

SELECT @SizeMB = size / 128.
FROM sysfiles
WHERE NAME = @DBFileName

SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

SELECT [StartFileSize] = @SizeMB
	,[StartUsedSpace] = @UsedMB
	,[DBFileName] = @DBFileName

WHILE @SizeMB > @UsedMB + @TargetFreeMB + @ShrinkIncrementMB

BEGIN
	SET @sql = 'dbcc shrinkfile ( ' + @DBFileName + ', ' + convert(VARCHAR(20), @SizeMB - @ShrinkIncrementMB) + ' ) '

	PRINT 'Start ' + @sql
	PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

	EXEC (@sql)

	PRINT 'Done ' + @sql
	PRINT 'at ' + convert(VARCHAR(30), getdate(), 121)

	SELECT @SizeMB = size / 128.
	FROM sysfiles
	WHERE NAME = @DBFileName

	SELECT @UsedMB = fileproperty(@DBFileName, 'SpaceUsed') / 128.

	SELECT [FileSize] = @SizeMB
		,[UsedSpace] = @UsedMB
		,[DBFileName] = @DBFileName
END

SELECT [EndFileSize] = @SizeMB
	,[EndUsedSpace] = @UsedMB
	,[DBFileName] = @DBFileName

SELECT [FileSizeMB] = convert(NUMERIC(10, 2), round(a.size / 128., 2))

	,[UsedSpaceMB] = convert(NUMERIC(10, 2), round(fileproperty a.NAME, 'SpaceUsed') / 128., 2))

,[UnusedSpaceMB] = convert(NUMERIC(10, 2), round((a.size - fileproperty(a.NAME, 'SpaceUsed')) / 128., 2))

,[DBFileName] = a.NAME

FROM sysfiles a